1 /***************************************************************************/
5 /* FreeType Cache Manager (body). */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 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
);
154 FT_CALLBACK_TABLE_DEF
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
,
190 return FTC_Err_Invalid_Argument
;
195 return FTC_Err_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
);
293 FT_CALLBACK_TABLE_DEF
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
,
317 return FTC_Err_Invalid_Argument
;
322 return FTC_Err_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 FTC_Err_Invalid_Library_Handle
;
369 memory
= library
->memory
;
371 if ( FT_NEW( manager
) )
374 if ( max_faces
== 0 )
375 max_faces
= FTC_MAX_FACES_DEFAULT
;
377 if ( max_sizes
== 0 )
378 max_sizes
= FTC_MAX_SIZES_DEFAULT
;
380 if ( max_bytes
== 0 )
381 max_bytes
= FTC_MAX_BYTES_DEFAULT
;
383 manager
->library
= library
;
384 manager
->memory
= memory
;
385 manager
->max_weight
= max_bytes
;
387 manager
->request_face
= requester
;
388 manager
->request_data
= req_data
;
390 FTC_MruList_Init( &manager
->faces
,
391 &ftc_face_list_class
,
396 FTC_MruList_Init( &manager
->sizes
,
397 &ftc_size_list_class
,
409 /* documentation is in ftcache.h */
411 FT_EXPORT_DEF( void )
412 FTC_Manager_Done( FTC_Manager manager
)
418 if ( !manager
|| !manager
->library
)
421 memory
= manager
->memory
;
423 /* now discard all caches */
424 for (idx
= manager
->num_caches
; idx
-- > 0; )
426 FTC_Cache cache
= manager
->caches
[idx
];
431 cache
->clazz
.cache_done( cache
);
433 manager
->caches
[idx
] = NULL
;
436 manager
->num_caches
= 0;
438 /* discard faces and sizes */
439 FTC_MruList_Done( &manager
->sizes
);
440 FTC_MruList_Done( &manager
->faces
);
442 manager
->library
= NULL
;
443 manager
->memory
= NULL
;
449 /* documentation is in ftcache.h */
451 FT_EXPORT_DEF( void )
452 FTC_Manager_Reset( FTC_Manager manager
)
456 FTC_MruList_Reset( &manager
->sizes
);
457 FTC_MruList_Reset( &manager
->faces
);
459 /* XXX: FIXME: flush the caches? */
463 #ifdef FT_DEBUG_ERROR
466 FTC_Manager_Check( FTC_Manager manager
)
468 FTC_Node node
, first
;
471 first
= manager
->nodes_list
;
473 /* check node weights */
483 FTC_Cache cache
= manager
->caches
[node
->cache_index
];
486 if ( (FT_UInt
)node
->cache_index
>= manager
->num_caches
)
487 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
488 node
->cache_index
));
490 weight
+= cache
->clazz
.node_weight( node
, cache
);
492 node
= FTC_NODE__NEXT( node
);
494 } while ( node
!= first
);
496 if ( weight
!= manager
->cur_weight
)
497 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
498 manager
->cur_weight
, weight
));
501 /* check circular list */
511 node
= FTC_NODE__NEXT( node
);
513 } while ( node
!= first
);
515 if ( count
!= manager
->num_nodes
)
516 FT_TRACE0(( "FTC_Manager_Check:"
517 " invalid cache node count %d instead of %d\n",
518 manager
->num_nodes
, count
));
522 #endif /* FT_DEBUG_ERROR */
525 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
526 /* that are not referenced anymore in order to limit the total */
527 /* memory used by the cache. */
529 /* documentation is in ftcmanag.h */
532 FTC_Manager_Compress( FTC_Manager manager
)
534 FTC_Node node
, first
;
540 first
= manager
->nodes_list
;
542 #ifdef FT_DEBUG_ERROR
543 FTC_Manager_Check( manager
);
545 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
546 manager
->cur_weight
, manager
->max_weight
,
547 manager
->num_nodes
));
550 if ( manager
->cur_weight
< manager
->max_weight
|| first
== NULL
)
553 /* go to last node -- it's a circular list */
554 node
= FTC_NODE__PREV( first
);
560 prev
= ( node
== first
) ? NULL
: FTC_NODE__PREV( node
);
562 if ( node
->ref_count
<= 0 )
563 ftc_node_destroy( node
, manager
);
567 } while ( node
&& manager
->cur_weight
> manager
->max_weight
);
571 /* documentation is in ftcmanag.h */
573 FT_LOCAL_DEF( FT_Error
)
574 FTC_Manager_RegisterCache( FTC_Manager manager
,
575 FTC_CacheClass clazz
,
578 FT_Error error
= FTC_Err_Invalid_Argument
;
579 FTC_Cache cache
= NULL
;
582 if ( manager
&& clazz
&& acache
)
584 FT_Memory memory
= manager
->memory
;
587 if ( manager
->num_caches
>= FTC_MAX_CACHES
)
589 error
= FTC_Err_Too_Many_Caches
;
590 FT_ERROR(( "FTC_Manager_RegisterCache:"
591 " too many registered caches\n" ));
595 if ( !FT_ALLOC( cache
, clazz
->cache_size
) )
597 cache
->manager
= manager
;
598 cache
->memory
= memory
;
599 cache
->clazz
= clazz
[0];
600 cache
->org_class
= clazz
;
602 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
603 /* IF IT IS NOT SET CORRECTLY */
604 cache
->index
= manager
->num_caches
;
606 error
= clazz
->cache_init( cache
);
609 clazz
->cache_done( cache
);
614 manager
->caches
[manager
->num_caches
++] = cache
;
625 FT_LOCAL_DEF( FT_UInt
)
626 FTC_Manager_FlushN( FTC_Manager manager
,
629 FTC_Node first
= manager
->nodes_list
;
634 /* try to remove `count' nodes from the list */
635 if ( first
== NULL
) /* empty list! */
638 /* go to last node - it's a circular list */
639 node
= FTC_NODE__PREV(first
);
640 for ( result
= 0; result
< count
; )
642 FTC_Node prev
= FTC_NODE__PREV( node
);
645 /* don't touch locked nodes */
646 if ( node
->ref_count
<= 0 )
648 ftc_node_destroy( node
, manager
);
661 /* documentation is in ftcache.h */
663 FT_EXPORT_DEF( void )
664 FTC_Manager_RemoveFaceID( FTC_Manager manager
,
669 /* this will remove all FTC_SizeNode that correspond to
670 * the face_id as well
672 FTC_MruList_RemoveSelection( &manager
->faces
,
673 (FTC_MruNode_CompareFunc
)NULL
,
676 for ( nn
= 0; nn
< manager
->num_caches
; nn
++ )
677 FTC_Cache_RemoveFaceID( manager
->caches
[nn
], face_id
);
681 /* documentation is in ftcache.h */
683 FT_EXPORT_DEF( void )
684 FTC_Node_Unref( FTC_Node node
,
685 FTC_Manager manager
)
687 if ( node
&& (FT_UInt
)node
->cache_index
< manager
->num_caches
)
692 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
694 FT_EXPORT_DEF( FT_Error
)
695 FTC_Manager_Lookup_Face( FTC_Manager manager
,
699 return FTC_Manager_LookupFace( manager
, face_id
, aface
);
703 FT_EXPORT( FT_Error
)
704 FTC_Manager_Lookup_Size( FTC_Manager manager
,
709 FTC_ScalerRec scaler
;
715 scaler
.face_id
= font
->face_id
;
716 scaler
.width
= font
->pix_width
;
717 scaler
.height
= font
->pix_height
;
722 error
= FTC_Manager_LookupSize( manager
, &scaler
, &size
);
740 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */