1 /***************************************************************************/
5 /* FreeType Cache Manager (body). */
7 /* Copyright 2000-2006, 2008-2010, 2013, 2014 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 /***************************************************************************/
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
29 #ifdef FT_CONFIG_OPTION_PIC
30 #error "cache system does not support PIC yet"
35 #define FT_COMPONENT trace_cache
37 #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
41 ftc_scaler_lookup_size( FTC_Manager manager,
50 error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
54 error = FT_New_Size( face, &size );
58 FT_Activate_Size( size );
61 error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
63 error = FT_Set_Char_Size( face, scaler->width, scaler->height,
64 scaler->x_res, scaler->y_res );
77 typedef struct FTC_SizeNodeRec_
83 } FTC_SizeNodeRec, *FTC_SizeNode;
85 #define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
88 FT_CALLBACK_DEF( void )
89 ftc_size_node_done( FTC_MruNode ftcnode,
92 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
93 FT_Size size = node->size;
102 FT_CALLBACK_DEF( FT_Bool )
103 ftc_size_node_compare( FTC_MruNode ftcnode,
104 FT_Pointer ftcscaler )
106 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
107 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
108 FTC_Scaler scaler0 = &node->scaler;
111 if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
113 FT_Activate_Size( node->size );
120 FT_CALLBACK_DEF( FT_Error )
121 ftc_size_node_init( FTC_MruNode ftcnode,
122 FT_Pointer ftcscaler,
123 FT_Pointer ftcmanager )
125 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
126 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
127 FTC_Manager manager = (FTC_Manager)ftcmanager;
130 node->scaler = scaler[0];
132 return ftc_scaler_lookup_size( manager, scaler, &node->size );
136 FT_CALLBACK_DEF( FT_Error )
137 ftc_size_node_reset( FTC_MruNode ftcnode,
138 FT_Pointer ftcscaler,
139 FT_Pointer ftcmanager )
141 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
142 FTC_Scaler scaler = (FTC_Scaler)ftcscaler;
143 FTC_Manager manager = (FTC_Manager)ftcmanager;
146 FT_Done_Size( node->size );
148 node->scaler = scaler[0];
150 return ftc_scaler_lookup_size( manager, scaler, &node->size );
155 const FTC_MruListClassRec ftc_size_list_class =
157 sizeof ( FTC_SizeNodeRec ),
158 ftc_size_node_compare,
165 /* helper function used by ftc_face_node_done */
167 ftc_size_node_compare_faceid( FTC_MruNode ftcnode,
168 FT_Pointer ftcface_id )
170 FTC_SizeNode node = (FTC_SizeNode)ftcnode;
171 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
174 return FT_BOOL( node->scaler.face_id == face_id );
178 /* documentation is in ftcache.h */
180 FT_EXPORT_DEF( FT_Error )
181 FTC_Manager_LookupSize( FTC_Manager manager,
189 if ( !asize || !scaler )
190 return FT_THROW( Invalid_Argument );
195 return FT_THROW( Invalid_Cache_Handle );
199 FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
203 error = FTC_MruList_Lookup( &manager->sizes, scaler, &mrunode );
207 *asize = FTC_SIZE_NODE( mrunode )->size;
213 /*************************************************************************/
214 /*************************************************************************/
216 /***** FACE MRU IMPLEMENTATION *****/
218 /*************************************************************************/
219 /*************************************************************************/
221 typedef struct FTC_FaceNodeRec_
227 } FTC_FaceNodeRec, *FTC_FaceNode;
229 #define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
232 FT_CALLBACK_DEF( FT_Error )
233 ftc_face_node_init( FTC_MruNode ftcnode,
234 FT_Pointer ftcface_id,
235 FT_Pointer ftcmanager )
237 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
238 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
239 FTC_Manager manager = (FTC_Manager)ftcmanager;
243 node->face_id = face_id;
245 error = manager->request_face( face_id,
247 manager->request_data,
251 /* destroy initial size object; it will be re-created later */
252 if ( node->face->size )
253 FT_Done_Size( node->face->size );
260 FT_CALLBACK_DEF( void )
261 ftc_face_node_done( FTC_MruNode ftcnode,
262 FT_Pointer ftcmanager )
264 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
265 FTC_Manager manager = (FTC_Manager)ftcmanager;
268 /* we must begin by removing all scalers for the target face */
269 /* from the manager's list */
270 FTC_MruList_RemoveSelection( &manager->sizes,
271 ftc_size_node_compare_faceid,
274 /* all right, we can discard the face now */
275 FT_Done_Face( node->face );
277 node->face_id = NULL;
281 FT_CALLBACK_DEF( FT_Bool )
282 ftc_face_node_compare( FTC_MruNode ftcnode,
283 FT_Pointer ftcface_id )
285 FTC_FaceNode node = (FTC_FaceNode)ftcnode;
286 FTC_FaceID face_id = (FTC_FaceID)ftcface_id;
289 return FT_BOOL( node->face_id == face_id );
294 const FTC_MruListClassRec ftc_face_list_class =
296 sizeof ( FTC_FaceNodeRec),
298 ftc_face_node_compare,
300 0, /* FTC_MruNode_ResetFunc */
305 /* documentation is in ftcache.h */
307 FT_EXPORT_DEF( FT_Error )
308 FTC_Manager_LookupFace( FTC_Manager manager,
316 if ( !aface || !face_id )
317 return FT_THROW( Invalid_Argument );
322 return FT_THROW( Invalid_Cache_Handle );
324 /* we break encapsulation for the sake of speed */
327 FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
331 error = FTC_MruList_Lookup( &manager->faces, face_id, &mrunode );
335 *aface = FTC_FACE_NODE( mrunode )->face;
341 /*************************************************************************/
342 /*************************************************************************/
344 /***** CACHE MANAGER ROUTINES *****/
346 /*************************************************************************/
347 /*************************************************************************/
350 /* documentation is in ftcache.h */
352 FT_EXPORT_DEF( FT_Error )
353 FTC_Manager_New( FT_Library library,
357 FTC_Face_Requester requester,
359 FTC_Manager *amanager )
363 FTC_Manager manager = 0;
367 return FT_THROW( Invalid_Library_Handle );
369 if ( !amanager || !requester )
370 return FT_THROW( Invalid_Argument );
372 memory = library->memory;
374 if ( FT_NEW( manager ) )
377 if ( max_faces == 0 )
378 max_faces = FTC_MAX_FACES_DEFAULT;
380 if ( max_sizes == 0 )
381 max_sizes = FTC_MAX_SIZES_DEFAULT;
383 if ( max_bytes == 0 )
384 max_bytes = FTC_MAX_BYTES_DEFAULT;
386 manager->library = library;
387 manager->memory = memory;
388 manager->max_weight = max_bytes;
390 manager->request_face = requester;
391 manager->request_data = req_data;
393 FTC_MruList_Init( &manager->faces,
394 &ftc_face_list_class,
399 FTC_MruList_Init( &manager->sizes,
400 &ftc_size_list_class,
412 /* documentation is in ftcache.h */
414 FT_EXPORT_DEF( void )
415 FTC_Manager_Done( FTC_Manager manager )
421 if ( !manager || !manager->library )
424 memory = manager->memory;
426 /* now discard all caches */
427 for (idx = manager->num_caches; idx-- > 0; )
429 FTC_Cache cache = manager->caches[idx];
434 cache->clazz.cache_done( cache );
436 manager->caches[idx] = NULL;
439 manager->num_caches = 0;
441 /* discard faces and sizes */
442 FTC_MruList_Done( &manager->sizes );
443 FTC_MruList_Done( &manager->faces );
445 manager->library = NULL;
446 manager->memory = NULL;
452 /* documentation is in ftcache.h */
454 FT_EXPORT_DEF( void )
455 FTC_Manager_Reset( FTC_Manager manager )
460 FTC_MruList_Reset( &manager->sizes );
461 FTC_MruList_Reset( &manager->faces );
463 FTC_Manager_FlushN( manager, manager->num_nodes );
467 #ifdef FT_DEBUG_ERROR
470 FTC_Manager_Check( FTC_Manager manager )
472 FTC_Node node, first;
475 first = manager->nodes_list;
477 /* check node weights */
480 FT_Offset weight = 0;
487 FTC_Cache cache = manager->caches[node->cache_index];
490 if ( (FT_UInt)node->cache_index >= manager->num_caches )
491 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
492 node->cache_index ));
494 weight += cache->clazz.node_weight( node, cache );
496 node = FTC_NODE__NEXT( node );
498 } while ( node != first );
500 if ( weight != manager->cur_weight )
501 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
502 manager->cur_weight, weight ));
505 /* check circular list */
515 node = FTC_NODE__NEXT( node );
517 } while ( node != first );
519 if ( count != manager->num_nodes )
520 FT_TRACE0(( "FTC_Manager_Check:"
521 " invalid cache node count %d instead of %d\n",
522 manager->num_nodes, count ));
526 #endif /* FT_DEBUG_ERROR */
529 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
530 /* that are not referenced anymore in order to limit the total */
531 /* memory used by the cache. */
533 /* documentation is in ftcmanag.h */
536 FTC_Manager_Compress( FTC_Manager manager )
538 FTC_Node node, first;
544 first = manager->nodes_list;
546 #ifdef FT_DEBUG_ERROR
547 FTC_Manager_Check( manager );
549 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
550 manager->cur_weight, manager->max_weight,
551 manager->num_nodes ));
554 if ( manager->cur_weight < manager->max_weight || first == NULL )
557 /* go to last node -- it's a circular list */
558 node = FTC_NODE__PREV( first );
564 prev = ( node == first ) ? NULL : FTC_NODE__PREV( node );
566 if ( node->ref_count <= 0 )
567 ftc_node_destroy( node, manager );
571 } while ( node && manager->cur_weight > manager->max_weight );
575 /* documentation is in ftcmanag.h */
577 FT_LOCAL_DEF( FT_Error )
578 FTC_Manager_RegisterCache( FTC_Manager manager,
579 FTC_CacheClass clazz,
582 FT_Error error = FT_ERR( Invalid_Argument );
583 FTC_Cache cache = NULL;
586 if ( manager && clazz && acache )
588 FT_Memory memory = manager->memory;
591 if ( manager->num_caches >= FTC_MAX_CACHES )
593 error = FT_THROW( Too_Many_Caches );
594 FT_ERROR(( "FTC_Manager_RegisterCache:"
595 " too many registered caches\n" ));
599 if ( !FT_ALLOC( cache, clazz->cache_size ) )
601 cache->manager = manager;
602 cache->memory = memory;
603 cache->clazz = clazz[0];
604 cache->org_class = clazz;
606 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
607 /* IF IT IS NOT SET CORRECTLY */
608 cache->index = manager->num_caches;
610 error = clazz->cache_init( cache );
613 clazz->cache_done( cache );
618 manager->caches[manager->num_caches++] = cache;
629 FT_LOCAL_DEF( FT_UInt )
630 FTC_Manager_FlushN( FTC_Manager manager,
633 FTC_Node first = manager->nodes_list;
638 /* try to remove `count' nodes from the list */
639 if ( first == NULL ) /* empty list! */
642 /* go to last node - it's a circular list */
643 node = FTC_NODE__PREV(first);
644 for ( result = 0; result < count; )
646 FTC_Node prev = FTC_NODE__PREV( node );
649 /* don't touch locked nodes */
650 if ( node->ref_count <= 0 )
652 ftc_node_destroy( node, manager );
665 /* documentation is in ftcache.h */
667 FT_EXPORT_DEF( void )
668 FTC_Manager_RemoveFaceID( FTC_Manager manager,
674 if ( !manager || !face_id )
677 /* this will remove all FTC_SizeNode that correspond to
678 * the face_id as well
680 FTC_MruList_RemoveSelection( &manager->faces,
681 ftc_face_node_compare,
684 for ( nn = 0; nn < manager->num_caches; nn++ )
685 FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
689 /* documentation is in ftcache.h */
691 FT_EXPORT_DEF( void )
692 FTC_Node_Unref( FTC_Node node,
693 FTC_Manager manager )
697 (FT_UInt)node->cache_index < manager->num_caches )