The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / ftcchunk.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcchunk.c                                                             */
4 /*                                                                         */
5 /*    FreeType chunk cache cache (body).                                   */
6 /*                                                                         */
7 /*  Copyright 2000-2001 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 #include <ft2build.h>
20 #include FT_CACHE_H
21 #include FT_CACHE_INTERNAL_CHUNK_H
22 #include FT_LIST_H
23 #include FT_ERRORS_H
24 #include FT_INTERNAL_OBJECTS_H
25
26 #include "ftcerror.h"
27
28
29   /*************************************************************************/
30   /*************************************************************************/
31   /*****                                                               *****/
32   /*****                      GLYPH NODES                              *****/
33   /*****                                                               *****/
34   /*************************************************************************/
35   /*************************************************************************/
36
37
38   /* create a new chunk node, setting its cache index and ref count */
39   FT_EXPORT_DEF( FT_Error )
40   FTC_ChunkNode_Init( FTC_ChunkNode  node,
41                       FTC_ChunkSet   cset,
42                       FT_UInt        index,
43                       FT_Bool        alloc )
44   {
45     FTC_Chunk_Cache      cache = cset->cache;
46     FTC_CacheNode_Data*  data  = FTC_CACHENODE_TO_DATA_P( &node->root );
47     FT_Error             error = 0;
48
49
50     data->cache_index  = (FT_UShort)cache->root.cache_index;
51     data->ref_count    = (FT_Short) 0;
52     node->cset         = cset;
53     node->cset_index   = (FT_UShort)index;
54     node->num_elements = (unsigned short)(
55                           ( index + 1 < cset->num_chunks )
56                             ? cset->element_count
57                             : cset->element_max - cset->element_count*index );
58     if ( alloc )
59     {
60       /* allocate elements array */
61       FT_Memory   memory;
62
63
64       memory = cache->root.memory;
65       error  = MEM_Alloc( node->elements,
66                           cset->element_size * cset->element_count );
67     }
68
69     return error;
70   }
71
72
73   FT_EXPORT_DEF( void )
74   FTC_ChunkNode_Destroy( FTC_ChunkNode  node )
75   {
76     FTC_ChunkSet  cset = node->cset;
77
78
79     /* remove from parent set table */
80     cset->chunks[node->cset_index] = 0;
81
82     /* destroy the node */
83     cset->clazz->destroy_node( node );
84   }
85
86
87   FT_EXPORT_DEF( FT_ULong )
88   FTC_ChunkNode_Size( FTC_ChunkNode  node )
89   {
90     FTC_ChunkSet  cset = node->cset;
91
92
93     return cset->clazz->size_node( node );
94   }
95
96
97   FT_CALLBACK_TABLE_DEF
98   const FTC_CacheNode_Class  ftc_chunk_cache_node_class =
99   {
100     (FTC_CacheNode_SizeFunc)   FTC_ChunkNode_Size,
101     (FTC_CacheNode_DestroyFunc)FTC_ChunkNode_Destroy
102   };
103
104
105   /*************************************************************************/
106   /*************************************************************************/
107   /*****                                                               *****/
108   /*****                      CHUNK SETS                               *****/
109   /*****                                                               *****/
110   /*************************************************************************/
111   /*************************************************************************/
112
113
114   FT_EXPORT_DEF( FT_Error )
115   FTC_ChunkSet_New( FTC_Chunk_Cache  cache,
116                     FT_Pointer       type,
117                     FTC_ChunkSet    *aset )
118   {
119     FT_Error      error;
120     FT_Memory     memory  = cache->root.memory;
121     FTC_Manager   manager = cache->root.manager;
122     FTC_ChunkSet  cset    = 0;
123
124     FTC_Chunk_Cache_Class*  ccache_class;
125     FTC_ChunkSet_Class*     clazz;
126
127
128     ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz;
129     clazz        = ccache_class->cset_class;
130
131     *aset = 0;
132
133     if ( ALLOC( cset, clazz->cset_byte_size ) )
134       goto Exit;
135
136     cset->cache   = cache;
137     cset->manager = manager;
138     cset->memory  = memory;
139     cset->clazz   = clazz;
140
141     /* now compute element_max, element_count and element_size */
142     error = clazz->sizes( cset, type );
143     if ( error )
144       goto Exit;
145
146     /* compute maximum number of nodes */
147     cset->num_chunks = ( cset->element_max + cset->element_count - 1 ) /
148                        cset->element_count;
149
150     /* allocate chunk pointers table */
151     if ( ALLOC_ARRAY( cset->chunks, cset->num_chunks, FTC_ChunkNode ) )
152       goto Exit;
153
154     /* initialize set by type if needed */
155     if ( clazz->init )
156     {
157       error = clazz->init( cset, type );
158       if ( error )
159         goto Exit;
160     }
161
162     *aset = cset;
163
164   Exit:
165     if ( error && cset )
166     {
167       FREE( cset->chunks );
168       FREE( cset );
169     }
170
171     return error;
172   }
173
174
175   FT_EXPORT_DEF( void )
176   FTC_ChunkSet_Destroy( FTC_ChunkSet  cset )
177   {
178     FTC_Chunk_Cache      cache        = cset->cache;
179     FTC_Manager          manager      = cache->root.manager;
180     FT_List              glyphs_lru   = &manager->global_lru;
181     FTC_ChunkNode*       bucket       = cset->chunks;
182     FTC_ChunkNode*       bucket_limit = bucket + cset->num_chunks;
183     FT_Memory            memory       = cache->root.memory;
184
185     FTC_ChunkSet_Class*  clazz        = cset->clazz;
186
187
188     /* for each bucket, free the list of glyph nodes */
189     for ( ; bucket < bucket_limit; bucket++ )
190     {
191       FTC_ChunkNode  node = bucket[0];
192       FT_ListNode    lrunode;
193
194
195       if ( node )
196       {
197         lrunode = FTC_CHUNKNODE_TO_LRUNODE( node );
198
199         manager->num_bytes -= clazz->size_node( node );
200         manager->num_nodes--;
201
202         FT_List_Remove( glyphs_lru, lrunode );
203
204         clazz->destroy_node( node );
205
206         bucket[0] = 0;
207       }
208     }
209
210     if ( clazz->done )
211       clazz->done( cset );
212
213     FREE( cset->chunks );
214     FREE( cset );
215   }
216
217
218   FT_EXPORT_DEF( FT_Error )
219   FTC_ChunkSet_Lookup_Node( FTC_ChunkSet    cset,
220                             FT_UInt         glyph_index,
221                             FTC_ChunkNode  *anode,
222                             FT_UInt        *anindex )
223   {
224     FTC_Chunk_Cache      cache   = cset->cache;
225     FTC_Manager          manager = cache->root.manager;
226     FT_Error             error   = 0;
227
228     FTC_ChunkSet_Class*  clazz   = cset->clazz;
229
230
231     *anode = 0;
232
233     if ( glyph_index >= cset->element_max )
234       error = FTC_Err_Invalid_Argument;
235     else
236     {
237       FT_UInt         chunk_size  = cset->element_count;
238       FT_UInt         chunk_index = glyph_index / chunk_size;
239       FTC_ChunkNode*  pnode       = cset->chunks + chunk_index;
240       FTC_ChunkNode   node        = *pnode;
241
242
243       if ( !node )
244       {
245         /* we didn't found the glyph image; we will now create a new one */
246         error = clazz->new_node( cset, chunk_index, &node );
247         if ( error )
248           goto Exit;
249
250         /* store the new chunk in the cset's table */
251         *pnode = node;
252
253         /* insert the node at the start the global LRU glyph list */
254         FT_List_Insert( &manager->global_lru,
255                         FTC_CHUNKNODE_TO_LRUNODE( node ) );
256
257         manager->num_bytes += clazz->size_node( node );
258         manager->num_nodes++;
259
260         if ( manager->num_bytes > manager->max_bytes )
261         {
262           FTC_ChunkNode_Ref   ( node );
263           FTC_Manager_Compress( manager );
264           FTC_ChunkNode_Unref ( node );
265         }
266       }
267
268       *anode   = node;
269       *anindex = glyph_index - chunk_index * chunk_size;
270     }
271
272   Exit:
273     return error;
274   }
275
276
277   /*************************************************************************/
278   /*************************************************************************/
279   /*****                                                               *****/
280   /*****                   CHUNK SETS LRU CALLBACKS                    *****/
281   /*****                                                               *****/
282   /*************************************************************************/
283   /*************************************************************************/
284
285
286 #define FTC_CSET_LRU_GET_CACHE( lru )   \
287           ( (FTC_Chunk_Cache)((lru)->user_data) )
288
289 #define FTC_CSET_LRU_GET_MANAGER( lru ) \
290           FTC_CSET_LRU_GET_CACHE( lru )->manager
291
292 #define FTC_LRUNODE_CSET( node )        \
293           ( (FTC_ChunkSet)(node)->root.data )
294
295
296   FT_CALLBACK_DEF( FT_Error )
297   ftc_chunk_set_lru_init( FT_Lru      lru,
298                           FT_LruNode  node )
299   {
300     FTC_Chunk_Cache  cache = FTC_CSET_LRU_GET_CACHE( lru );
301     FT_Error         error;
302     FTC_ChunkSet     cset;
303
304
305     error = FTC_ChunkSet_New( cache,
306                               (FT_Pointer)node->key,
307                               &cset );
308     if ( !error )
309     {
310       /* good, now set the set index within the set object */
311       cset->cset_index = (FT_UInt)( node - lru->nodes );
312       node->root.data  = cset;
313     }
314
315     return error;
316   }
317
318
319   FT_CALLBACK_DEF( void )
320   ftc_chunk_set_lru_done( FT_Lru      lru,
321                           FT_LruNode  node )
322   {
323     FTC_ChunkSet  cset = FTC_LRUNODE_CSET( node );
324
325     FT_UNUSED( lru );
326
327
328     FTC_ChunkSet_Destroy( cset );
329   }
330
331
332   FT_CALLBACK_DEF( FT_Bool )
333   ftc_chunk_set_lru_compare( FT_LruNode  node,
334                              FT_LruKey   key )
335   {
336     FTC_ChunkSet  cset = FTC_LRUNODE_CSET( node );
337
338
339     return cset->clazz->compare( cset, (FT_Pointer)key );
340   }
341
342
343   FT_CALLBACK_TABLE_DEF
344   const FT_Lru_Class  ftc_chunk_set_lru_class =
345   {
346     sizeof( FT_LruRec ),
347     ftc_chunk_set_lru_init,
348     ftc_chunk_set_lru_done,
349     0,  /* no flush */
350     ftc_chunk_set_lru_compare
351   };
352
353
354   /*************************************************************************/
355   /*************************************************************************/
356   /*****                                                               *****/
357   /*****                   CHUNK CACHE OBJECTS                         *****/
358   /*****                                                               *****/
359   /*************************************************************************/
360   /*************************************************************************/
361
362
363   FT_EXPORT_DEF( FT_Error )
364   FTC_Chunk_Cache_Init( FTC_Chunk_Cache  cache )
365   {
366     FT_Memory  memory = cache->root.memory;
367     FT_Error   error;
368
369     FTC_Chunk_Cache_Class*  ccache_clazz;
370
371
372     /* set up root node_class to be used by manager */
373     cache->root.node_clazz =
374       (FTC_CacheNode_Class*)&ftc_chunk_cache_node_class;
375
376     /* setup `compare' shortcut */
377     ccache_clazz   = (FTC_Chunk_Cache_Class*)cache->root.clazz;
378     cache->compare = ccache_clazz->cset_class->compare;
379
380     error = FT_Lru_New( &ftc_chunk_set_lru_class,
381                         FTC_MAX_CHUNK_SETS,
382                         cache,
383                         memory,
384                         1, /* pre_alloc == TRUE */
385                         &cache->csets_lru );
386     return error;
387   }
388
389
390   FT_EXPORT_DEF( void )
391   FTC_Chunk_Cache_Done( FTC_Chunk_Cache  cache )
392   {
393     /* discard glyph sets */
394     FT_Lru_Done( cache->csets_lru );
395   }
396
397
398   FT_EXPORT_DEF( FT_Error )
399   FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache  cache,
400                           FT_Pointer       type,
401                           FT_UInt          gindex,
402                           FTC_ChunkNode   *anode,
403                           FT_UInt         *aindex )
404   {
405     FT_Error       error;
406     FTC_ChunkSet   cset;
407     FTC_ChunkNode  node;
408     FT_UInt        cindex;
409     FTC_Manager    manager;
410
411
412     /* check for valid `desc' delayed to FT_Lru_Lookup() */
413
414     if ( !cache || !anode || !aindex )
415       return FTC_Err_Invalid_Argument;
416
417     *anode  = 0;
418     *aindex = 0;
419     cset    = cache->last_cset;
420
421     if ( !cset || !cache->compare( cset, type ) )
422     {
423       error = FT_Lru_Lookup( cache->csets_lru,
424                              (FT_LruKey)type,
425                              (FT_Pointer*)&cset );
426       cache->last_cset = cset;
427       if ( error )
428         goto Exit;
429     }
430
431     error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
432     if ( error )
433       goto Exit;
434
435     /* now compress the manager's cache pool if needed */
436     manager = cache->root.manager;
437     if ( manager->num_bytes > manager->max_bytes )
438     {
439       FTC_ChunkNode_Ref   ( node );
440       FTC_Manager_Compress( manager );
441       FTC_ChunkNode_Unref ( node );
442     }
443
444     *anode  = node;
445     *aindex = cindex;
446
447   Exit:
448     return error;
449   }
450
451
452 /* END */