The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / ftcmanag.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftcmanag.c                                                             */
4 /*                                                                         */
5 /*    FreeType Cache Manager (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_MANAGER_H
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
24 #include FT_LIST_H
25 #include FT_SIZES_H
26
27 #include "ftcerror.h"
28
29
30 #undef  FT_COMPONENT
31 #define FT_COMPONENT  trace_cache
32
33 #define FTC_LRU_GET_MANAGER( lru )  (FTC_Manager)lru->user_data
34
35
36   /*************************************************************************/
37   /*************************************************************************/
38   /*****                                                               *****/
39   /*****               FACE & SIZE LRU CALLBACKS                       *****/
40   /*****                                                               *****/
41   /*************************************************************************/
42   /*************************************************************************/
43
44
45   FT_CALLBACK_DEF( FT_Error )
46   ftc_manager_init_face( FT_Lru      lru,
47                          FT_LruNode  node )
48   {
49     FTC_Manager  manager = FTC_LRU_GET_MANAGER( lru );
50     FT_Error     error;
51     FT_Face      face;
52
53
54     error = manager->request_face( (FTC_FaceID)node->key,
55                                    manager->library,
56                                    manager->request_data,
57                                    (FT_Face*)&node->root.data );
58     if ( !error )
59     {
60       /* destroy initial size object; it will be re-created later */
61       face = (FT_Face)node->root.data;
62       if ( face->size )
63         FT_Done_Size( face->size );
64     }
65
66     return error;
67   }
68
69
70   /* helper function for ftc_manager_done_face() */
71   FT_CALLBACK_DEF( FT_Bool )
72   ftc_manager_size_selector( FT_Lru      lru,
73                              FT_LruNode  node,
74                              FT_Pointer  data )
75   {
76     FT_UNUSED( lru );
77
78     return FT_BOOL( ((FT_Size)node->root.data)->face == (FT_Face)data );
79   }
80
81
82   FT_CALLBACK_DEF( void )
83   ftc_manager_done_face( FT_Lru      lru,
84                          FT_LruNode  node )
85   {
86     FTC_Manager  manager = FTC_LRU_GET_MANAGER( lru );
87     FT_Face      face    = (FT_Face)node->root.data;
88
89
90     /* we must begin by removing all sizes for the target face */
91     /* from the manager's list                                 */
92     FT_Lru_Remove_Selection( manager->sizes_lru,
93                              ftc_manager_size_selector,
94                              face );
95
96     /* all right, we can discard the face now */
97     FT_Done_Face( face );
98     node->root.data = 0;
99   }
100
101
102   typedef struct  FTC_FontRequest_
103   {
104     FT_Face    face;
105     FT_UShort  width;
106     FT_UShort  height;
107
108   } FTC_FontRequest;
109
110
111   FT_CALLBACK_DEF( FT_Error )
112   ftc_manager_init_size( FT_Lru      lru,
113                          FT_LruNode  node )
114   {
115     FTC_FontRequest*  font_req = (FTC_FontRequest*)node->key;
116     FT_Size           size;
117     FT_Error          error;
118     FT_Face           face = font_req->face;
119
120     FT_UNUSED( lru );
121
122
123     node->root.data = 0;
124     error = FT_New_Size( face, &size );
125     if ( !error )
126     {
127       FT_Activate_Size( size );
128       error = FT_Set_Pixel_Sizes( face,
129                                   font_req->width,
130                                   font_req->height );
131       if ( error )
132         FT_Done_Size( size );
133       else
134         node->root.data = size;
135     }
136     return error;
137   }
138
139
140   FT_CALLBACK_DEF( void )
141   ftc_manager_done_size( FT_Lru      lru,
142                          FT_LruNode  node )
143   {
144     FT_UNUSED( lru );
145
146     FT_Done_Size( (FT_Size)node->root.data );
147     node->root.data = 0;
148   }
149
150
151   FT_CALLBACK_DEF( FT_Error )
152   ftc_manager_flush_size( FT_Lru      lru,
153                           FT_LruNode  node,
154                           FT_LruKey   key )
155   {
156     FTC_FontRequest*  req  = (FTC_FontRequest*)key;
157     FT_Size           size = (FT_Size)node->root.data;
158     FT_Error          error;
159
160
161     if ( size->face == req->face )
162     {
163       FT_Activate_Size( size );
164       error = FT_Set_Pixel_Sizes( req->face, req->width, req->height );
165       if ( error )
166         FT_Done_Size( size );
167     }
168     else
169     {
170       FT_Done_Size( size );
171       node->key = key;
172       error = ftc_manager_init_size( lru, node );
173     }
174     return error;
175   }
176
177
178   FT_CALLBACK_DEF( FT_Bool )
179   ftc_manager_compare_size( FT_LruNode  node,
180                             FT_LruKey   key )
181   {
182     FTC_FontRequest*  req  = (FTC_FontRequest*)key;
183     FT_Size           size = (FT_Size)node->root.data;
184
185     FT_UNUSED( node );
186
187
188     return FT_BOOL( size->face           == req->face   &&
189                     size->metrics.x_ppem == req->width  &&
190                     size->metrics.y_ppem == req->height );
191   }
192
193
194   FT_CALLBACK_TABLE_DEF
195   const FT_Lru_Class  ftc_face_lru_class =
196   {
197     sizeof ( FT_LruRec ),
198     ftc_manager_init_face,
199     ftc_manager_done_face,
200     0,
201     0
202   };
203
204
205   FT_CALLBACK_TABLE_DEF
206   const FT_Lru_Class  ftc_size_lru_class =
207   {
208     sizeof ( FT_LruRec ),
209     ftc_manager_init_size,
210     ftc_manager_done_size,
211     ftc_manager_flush_size,
212     ftc_manager_compare_size
213   };
214
215
216   /* documentation is in ftcache.h */
217
218   FT_EXPORT_DEF( FT_Error )
219   FTC_Manager_New( FT_Library          library,
220                    FT_UInt             max_faces,
221                    FT_UInt             max_sizes,
222                    FT_ULong            max_bytes,
223                    FTC_Face_Requester  requester,
224                    FT_Pointer          req_data,
225                    FTC_Manager        *amanager )
226   {
227     FT_Error     error;
228     FT_Memory    memory;
229     FTC_Manager  manager = 0;
230
231
232     if ( !library )
233       return FTC_Err_Invalid_Library_Handle;
234
235     memory = library->memory;
236
237     if ( ALLOC( manager, sizeof ( *manager ) ) )
238       goto Exit;
239
240     if ( max_faces == 0 )
241       max_faces = FTC_MAX_FACES_DEFAULT;
242
243     if ( max_sizes == 0 )
244       max_sizes = FTC_MAX_SIZES_DEFAULT;
245
246     if ( max_bytes == 0 )
247       max_bytes = FTC_MAX_BYTES_DEFAULT;
248
249     error = FT_Lru_New( &ftc_face_lru_class,
250                         max_faces,
251                         manager,
252                         memory,
253                         1, /* pre_alloc = TRUE */
254                         (FT_Lru*)&manager->faces_lru );
255     if ( error )
256       goto Exit;
257
258     error = FT_Lru_New( &ftc_size_lru_class,
259                         max_sizes,
260                         manager,
261                         memory,
262                         1, /* pre_alloc = TRUE */
263                         (FT_Lru*)&manager->sizes_lru );
264     if ( error )
265       goto Exit;
266
267     manager->library      = library;
268     manager->max_bytes    = max_bytes;
269     manager->request_face = requester;
270     manager->request_data = req_data;
271
272     *amanager = manager;
273
274   Exit:
275     if ( error && manager )
276     {
277       FT_Lru_Done( manager->faces_lru );
278       FT_Lru_Done( manager->sizes_lru );
279       FREE( manager );
280     }
281
282     return error;
283   }
284
285
286   /* documentation is in ftcache.h */
287
288   FT_EXPORT_DEF( void )
289   FTC_Manager_Done( FTC_Manager  manager )
290   {
291     FT_Memory  memory;
292     FT_UInt    index;
293
294
295     if ( !manager || !manager->library )
296       return;
297
298     memory = manager->library->memory;
299
300     /* now discard all caches */
301     for (index = 0; index < FTC_MAX_CACHES; index++ )
302     {
303       FTC_Cache  cache = manager->caches[index];
304
305
306       if ( cache )
307       {
308         cache->clazz->done_cache( cache );
309         FREE( cache );
310         manager->caches[index] = 0;
311       }
312     }
313
314     /* discard faces and sizes */
315     FT_Lru_Done( manager->faces_lru );
316     manager->faces_lru = 0;
317
318     FT_Lru_Done( manager->sizes_lru );
319     manager->sizes_lru = 0;
320
321     FREE( manager );
322   }
323
324
325   /* documentation is in ftcache.h */
326
327   FT_EXPORT_DEF( void )
328   FTC_Manager_Reset( FTC_Manager  manager )
329   {
330     if (manager )
331     {
332       FT_Lru_Reset( manager->sizes_lru );
333       FT_Lru_Reset( manager->faces_lru );
334     }
335     /* XXX: FIXME: flush the caches? */
336   }
337
338
339   /* documentation is in ftcache.h */
340
341   FT_EXPORT_DEF( FT_Error )
342   FTC_Manager_Lookup_Face( FTC_Manager  manager,
343                            FTC_FaceID   face_id,
344                            FT_Face     *aface )
345   {
346     if ( !manager )
347       return FTC_Err_Invalid_Cache_Handle;
348
349     return  FT_Lru_Lookup( manager->faces_lru,
350                            (FT_LruKey)face_id,
351                            (FT_Pointer*)aface );
352   }
353
354
355   /* documentation is in ftcache.h */
356
357   FT_EXPORT_DEF( FT_Error )
358   FTC_Manager_Lookup_Size( FTC_Manager  manager,
359                            FTC_Font     font,
360                            FT_Face     *aface,
361                            FT_Size     *asize )
362   {
363     FTC_FontRequest  req;
364     FT_Error         error;
365
366
367     /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
368
369     if ( aface )
370       *aface = 0;
371
372     if ( asize )
373       *asize = 0;
374
375     error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
376     if ( !error )
377     {
378       FT_Size  size;
379
380
381       req.face   = *aface;
382       req.width  = font->pix_width;
383       req.height = font->pix_height;
384
385       error = FT_Lru_Lookup( manager->sizes_lru,
386                              (FT_LruKey)&req,
387                              (FT_Pointer*)&size );
388       if ( !error )
389       {
390         /* select the size as the current one for this face */
391         (*aface)->size = size;
392
393         if ( asize )
394           *asize = size;
395       }
396     }
397
398     return error;
399   }
400
401
402   /* `Compress' the manager's data, i.e., get rid of old cache nodes */
403   /* that are not referenced anymore in order to limit the total     */
404   /* memory used by the cache.                                       */
405
406   /* documentation is in ftcmanag.h */
407
408   FT_EXPORT_DEF( void )
409   FTC_Manager_Compress( FTC_Manager  manager )
410   {
411     FT_ListNode  node;
412
413
414     node = manager->global_lru.tail;
415     while ( manager->num_bytes > manager->max_bytes && node )
416     {
417       FTC_CacheNode        cache_node = FTC_LIST_TO_CACHENODE( node );
418       FTC_CacheNode_Data*  data       = FTC_CACHENODE_TO_DATA_P( cache_node );
419       FTC_Cache            cache;
420       FT_ListNode          prev       = node->prev;
421
422
423       if ( data->ref_count <= 0 )
424       {
425         /* ok, we are going to remove this node */
426         FT_List_Remove( &manager->global_lru, node );
427
428         /* finalize cache node */
429         cache = manager->caches[data->cache_index];
430         if ( cache )
431         {
432           FTC_CacheNode_Class*  clazz = cache->node_clazz;
433
434
435           manager->num_bytes -= clazz->size_node( cache_node,
436                                                   cache->cache_data );
437
438           clazz->destroy_node( cache_node, cache->cache_data );
439         }
440         else
441         {
442           /* this should never happen! */
443           FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" ));
444         }
445
446         /* check, just in case of general corruption :-) */
447         if ( manager->num_nodes <= 0 )
448           FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count!\n" ));
449         else
450           manager->num_nodes--;
451       }
452       node = prev;
453     }
454   }
455
456
457   FT_EXPORT_DEF( FT_Error )
458   FTC_Manager_Register_Cache( FTC_Manager       manager,
459                               FTC_Cache_Class*  clazz,
460                               FTC_Cache        *acache )
461   {
462     FT_Error  error = FTC_Err_Invalid_Argument;
463
464
465     if ( manager && clazz && acache )
466     {
467       FT_Memory  memory = manager->library->memory;
468       FTC_Cache  cache;
469       FT_UInt    index = 0;
470
471
472       /* by default, return 0 */
473       *acache = 0;
474
475       /* check for an empty cache slot in the manager's table */
476       for ( index = 0; index < FTC_MAX_CACHES; index++ )
477       {
478         if ( manager->caches[index] == 0 )
479           break;
480       }
481
482       /* return an error if there are too many registered caches */
483       if ( index >= FTC_MAX_CACHES )
484       {
485         error = FTC_Err_Too_Many_Caches;
486         FT_ERROR(( "FTC_Manager_Register_Cache:" ));
487         FT_ERROR(( " too many registered caches\n" ));
488         goto Exit;
489       }
490
491       if ( !ALLOC( cache, clazz->cache_byte_size ) )
492       {
493         cache->manager = manager;
494         cache->memory  = memory;
495         cache->clazz   = clazz;
496
497         /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
498         /* IF IT IS NOT SET CORRECTLY                         */
499         cache->cache_index = index;
500
501         if ( clazz->init_cache )
502           error = clazz->init_cache( cache );
503
504         if ( error )
505           FREE( cache );
506         else
507           manager->caches[index] = *acache = cache;
508       }
509     }
510
511   Exit:
512     return error;
513   }
514
515
516 /* END */