1 /***************************************************************************/
5 /* FreeType Cache Manager (body). */
7 /* Copyright 2000-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
21 #include FT_CACHE_MANAGER_H
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
31 #define FT_COMPONENT trace_cache
33 #define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data
36 /*************************************************************************/
37 /*************************************************************************/
39 /***** FACE & SIZE LRU CALLBACKS *****/
41 /*************************************************************************/
42 /*************************************************************************/
45 FT_CALLBACK_DEF( FT_Error )
46 ftc_manager_init_face( FT_Lru lru,
49 FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
54 error = manager->request_face( (FTC_FaceID)node->key,
56 manager->request_data,
57 (FT_Face*)&node->root.data );
60 /* destroy initial size object; it will be re-created later */
61 face = (FT_Face)node->root.data;
63 FT_Done_Size( face->size );
70 /* helper function for ftc_manager_done_face() */
71 FT_CALLBACK_DEF( FT_Bool )
72 ftc_manager_size_selector( FT_Lru lru,
78 return FT_BOOL( ((FT_Size)node->root.data)->face == (FT_Face)data );
82 FT_CALLBACK_DEF( void )
83 ftc_manager_done_face( FT_Lru lru,
86 FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
87 FT_Face face = (FT_Face)node->root.data;
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,
96 /* all right, we can discard the face now */
102 typedef struct FTC_FontRequest_
111 FT_CALLBACK_DEF( FT_Error )
112 ftc_manager_init_size( FT_Lru lru,
115 FTC_FontRequest* font_req = (FTC_FontRequest*)node->key;
118 FT_Face face = font_req->face;
124 error = FT_New_Size( face, &size );
127 FT_Activate_Size( size );
128 error = FT_Set_Pixel_Sizes( face,
132 FT_Done_Size( size );
134 node->root.data = size;
140 FT_CALLBACK_DEF( void )
141 ftc_manager_done_size( FT_Lru lru,
146 FT_Done_Size( (FT_Size)node->root.data );
151 FT_CALLBACK_DEF( FT_Error )
152 ftc_manager_flush_size( FT_Lru lru,
156 FTC_FontRequest* req = (FTC_FontRequest*)key;
157 FT_Size size = (FT_Size)node->root.data;
161 if ( size->face == req->face )
163 FT_Activate_Size( size );
164 error = FT_Set_Pixel_Sizes( req->face, req->width, req->height );
166 FT_Done_Size( size );
170 FT_Done_Size( size );
172 error = ftc_manager_init_size( lru, node );
178 FT_CALLBACK_DEF( FT_Bool )
179 ftc_manager_compare_size( FT_LruNode node,
182 FTC_FontRequest* req = (FTC_FontRequest*)key;
183 FT_Size size = (FT_Size)node->root.data;
188 return FT_BOOL( size->face == req->face &&
189 size->metrics.x_ppem == req->width &&
190 size->metrics.y_ppem == req->height );
194 FT_CALLBACK_TABLE_DEF
195 const FT_Lru_Class ftc_face_lru_class =
197 sizeof ( FT_LruRec ),
198 ftc_manager_init_face,
199 ftc_manager_done_face,
205 FT_CALLBACK_TABLE_DEF
206 const FT_Lru_Class ftc_size_lru_class =
208 sizeof ( FT_LruRec ),
209 ftc_manager_init_size,
210 ftc_manager_done_size,
211 ftc_manager_flush_size,
212 ftc_manager_compare_size
216 /* documentation is in ftcache.h */
218 FT_EXPORT_DEF( FT_Error )
219 FTC_Manager_New( FT_Library library,
223 FTC_Face_Requester requester,
225 FTC_Manager *amanager )
229 FTC_Manager manager = 0;
233 return FTC_Err_Invalid_Library_Handle;
235 memory = library->memory;
237 if ( ALLOC( manager, sizeof ( *manager ) ) )
240 if ( max_faces == 0 )
241 max_faces = FTC_MAX_FACES_DEFAULT;
243 if ( max_sizes == 0 )
244 max_sizes = FTC_MAX_SIZES_DEFAULT;
246 if ( max_bytes == 0 )
247 max_bytes = FTC_MAX_BYTES_DEFAULT;
249 error = FT_Lru_New( &ftc_face_lru_class,
253 1, /* pre_alloc = TRUE */
254 (FT_Lru*)&manager->faces_lru );
258 error = FT_Lru_New( &ftc_size_lru_class,
262 1, /* pre_alloc = TRUE */
263 (FT_Lru*)&manager->sizes_lru );
267 manager->library = library;
268 manager->max_bytes = max_bytes;
269 manager->request_face = requester;
270 manager->request_data = req_data;
275 if ( error && manager )
277 FT_Lru_Done( manager->faces_lru );
278 FT_Lru_Done( manager->sizes_lru );
286 /* documentation is in ftcache.h */
288 FT_EXPORT_DEF( void )
289 FTC_Manager_Done( FTC_Manager manager )
295 if ( !manager || !manager->library )
298 memory = manager->library->memory;
300 /* now discard all caches */
301 for (index = 0; index < FTC_MAX_CACHES; index++ )
303 FTC_Cache cache = manager->caches[index];
308 cache->clazz->done_cache( cache );
310 manager->caches[index] = 0;
314 /* discard faces and sizes */
315 FT_Lru_Done( manager->faces_lru );
316 manager->faces_lru = 0;
318 FT_Lru_Done( manager->sizes_lru );
319 manager->sizes_lru = 0;
325 /* documentation is in ftcache.h */
327 FT_EXPORT_DEF( void )
328 FTC_Manager_Reset( FTC_Manager manager )
332 FT_Lru_Reset( manager->sizes_lru );
333 FT_Lru_Reset( manager->faces_lru );
335 /* XXX: FIXME: flush the caches? */
339 /* documentation is in ftcache.h */
341 FT_EXPORT_DEF( FT_Error )
342 FTC_Manager_Lookup_Face( FTC_Manager manager,
347 return FTC_Err_Invalid_Cache_Handle;
349 return FT_Lru_Lookup( manager->faces_lru,
351 (FT_Pointer*)aface );
355 /* documentation is in ftcache.h */
357 FT_EXPORT_DEF( FT_Error )
358 FTC_Manager_Lookup_Size( FTC_Manager manager,
367 /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
375 error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
382 req.width = font->pix_width;
383 req.height = font->pix_height;
385 error = FT_Lru_Lookup( manager->sizes_lru,
387 (FT_Pointer*)&size );
390 /* select the size as the current one for this face */
391 (*aface)->size = size;
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. */
406 /* documentation is in ftcmanag.h */
408 FT_EXPORT_DEF( void )
409 FTC_Manager_Compress( FTC_Manager manager )
414 node = manager->global_lru.tail;
415 while ( manager->num_bytes > manager->max_bytes && node )
417 FTC_CacheNode cache_node = FTC_LIST_TO_CACHENODE( node );
418 FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( cache_node );
420 FT_ListNode prev = node->prev;
423 if ( data->ref_count <= 0 )
425 /* ok, we are going to remove this node */
426 FT_List_Remove( &manager->global_lru, node );
428 /* finalize cache node */
429 cache = manager->caches[data->cache_index];
432 FTC_CacheNode_Class* clazz = cache->node_clazz;
435 manager->num_bytes -= clazz->size_node( cache_node,
438 clazz->destroy_node( cache_node, cache->cache_data );
442 /* this should never happen! */
443 FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" ));
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" ));
450 manager->num_nodes--;
457 FT_EXPORT_DEF( FT_Error )
458 FTC_Manager_Register_Cache( FTC_Manager manager,
459 FTC_Cache_Class* clazz,
462 FT_Error error = FTC_Err_Invalid_Argument;
465 if ( manager && clazz && acache )
467 FT_Memory memory = manager->library->memory;
472 /* by default, return 0 */
475 /* check for an empty cache slot in the manager's table */
476 for ( index = 0; index < FTC_MAX_CACHES; index++ )
478 if ( manager->caches[index] == 0 )
482 /* return an error if there are too many registered caches */
483 if ( index >= FTC_MAX_CACHES )
485 error = FTC_Err_Too_Many_Caches;
486 FT_ERROR(( "FTC_Manager_Register_Cache:" ));
487 FT_ERROR(( " too many registered caches\n" ));
491 if ( !ALLOC( cache, clazz->cache_byte_size ) )
493 cache->manager = manager;
494 cache->memory = memory;
495 cache->clazz = clazz;
497 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
498 /* IF IT IS NOT SET CORRECTLY */
499 cache->cache_index = index;
501 if ( clazz->init_cache )
502 error = clazz->init_cache( cache );
507 manager->caches[index] = *acache = cache;