1 /***************************************************************************/
5 /* FreeType Cache Manager (body). */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006 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
31 #define FT_COMPONENT trace_cache
33 #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
37 ftc_scaler_lookup_size( FTC_Manager manager
,
46 error
= FTC_Manager_LookupFace( manager
, scaler
->face_id
, &face
);
50 error
= FT_New_Size( face
, &size
);
54 FT_Activate_Size( size
);
57 error
= FT_Set_Pixel_Sizes( face
, scaler
->width
, scaler
->height
);
59 error
= FT_Set_Char_Size( face
, scaler
->width
, scaler
->height
,
60 scaler
->x_res
, scaler
->y_res
);
73 typedef struct FTC_SizeNodeRec_
79 } FTC_SizeNodeRec
, *FTC_SizeNode
;
82 FT_CALLBACK_DEF( void )
83 ftc_size_node_done( FTC_MruNode ftcnode
,
86 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
87 FT_Size size
= node
->size
;
96 FT_CALLBACK_DEF( FT_Bool
)
97 ftc_size_node_compare( FTC_MruNode ftcnode
,
98 FT_Pointer ftcscaler
)
100 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
101 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
102 FTC_Scaler scaler0
= &node
->scaler
;
105 if ( FTC_SCALER_COMPARE( scaler0
, scaler
) )
107 FT_Activate_Size( node
->size
);
114 FT_CALLBACK_DEF( FT_Error
)
115 ftc_size_node_init( FTC_MruNode ftcnode
,
116 FT_Pointer ftcscaler
,
117 FT_Pointer ftcmanager
)
119 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
120 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
121 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
124 node
->scaler
= scaler
[0];
126 return ftc_scaler_lookup_size( manager
, scaler
, &node
->size
);
130 FT_CALLBACK_DEF( FT_Error
)
131 ftc_size_node_reset( FTC_MruNode ftcnode
,
132 FT_Pointer ftcscaler
,
133 FT_Pointer ftcmanager
)
135 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
136 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
137 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
140 FT_Done_Size( node
->size
);
142 node
->scaler
= scaler
[0];
144 return ftc_scaler_lookup_size( manager
, scaler
, &node
->size
);
148 FT_CALLBACK_TABLE_DEF
149 const FTC_MruListClassRec ftc_size_list_class
=
151 sizeof ( FTC_SizeNodeRec
),
152 ftc_size_node_compare
,
159 /* helper function used by ftc_face_node_done */
161 ftc_size_node_compare_faceid( FTC_MruNode ftcnode
,
162 FT_Pointer ftcface_id
)
164 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
165 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
168 return FT_BOOL( node
->scaler
.face_id
== face_id
);
172 /* documentation is in ftcache.h */
174 FT_EXPORT_DEF( FT_Error
)
175 FTC_Manager_LookupSize( FTC_Manager manager
,
184 return FTC_Err_Bad_Argument
;
189 return FTC_Err_Invalid_Cache_Handle
;
193 FTC_MRULIST_LOOKUP_CMP( &manager
->sizes
, scaler
, ftc_size_node_compare
,
197 error
= FTC_MruList_Lookup( &manager
->sizes
, scaler
, (FTC_MruNode
*)&node
);
207 /*************************************************************************/
208 /*************************************************************************/
210 /***** FACE MRU IMPLEMENTATION *****/
212 /*************************************************************************/
213 /*************************************************************************/
215 typedef struct FTC_FaceNodeRec_
221 } FTC_FaceNodeRec
, *FTC_FaceNode
;
224 FT_CALLBACK_DEF( FT_Error
)
225 ftc_face_node_init( FTC_MruNode ftcnode
,
226 FT_Pointer ftcface_id
,
227 FT_Pointer ftcmanager
)
229 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
230 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
231 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
235 node
->face_id
= face_id
;
237 error
= manager
->request_face( face_id
,
239 manager
->request_data
,
243 /* destroy initial size object; it will be re-created later */
244 if ( node
->face
->size
)
245 FT_Done_Size( node
->face
->size
);
252 FT_CALLBACK_DEF( void )
253 ftc_face_node_done( FTC_MruNode ftcnode
,
254 FT_Pointer ftcmanager
)
256 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
257 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
260 /* we must begin by removing all scalers for the target face */
261 /* from the manager's list */
262 FTC_MruList_RemoveSelection( &manager
->sizes
,
263 ftc_size_node_compare_faceid
,
266 /* all right, we can discard the face now */
267 FT_Done_Face( node
->face
);
269 node
->face_id
= NULL
;
273 FT_CALLBACK_DEF( FT_Bool
)
274 ftc_face_node_compare( FTC_MruNode ftcnode
,
275 FT_Pointer ftcface_id
)
277 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
278 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
281 return FT_BOOL( node
->face_id
== face_id
);
285 FT_CALLBACK_TABLE_DEF
286 const FTC_MruListClassRec ftc_face_list_class
=
288 sizeof ( FTC_FaceNodeRec
),
290 ftc_face_node_compare
,
292 0, /* FTC_MruNode_ResetFunc */
297 /* documentation is in ftcache.h */
299 FT_EXPORT_DEF( FT_Error
)
300 FTC_Manager_LookupFace( FTC_Manager manager
,
309 return FTC_Err_Bad_Argument
;
314 return FTC_Err_Invalid_Cache_Handle
;
316 /* we break encapsulation for the sake of speed */
319 FTC_MRULIST_LOOKUP_CMP( &manager
->faces
, face_id
, ftc_face_node_compare
,
323 error
= FTC_MruList_Lookup( &manager
->faces
, face_id
, (FTC_MruNode
*)&node
);
333 /*************************************************************************/
334 /*************************************************************************/
336 /***** CACHE MANAGER ROUTINES *****/
338 /*************************************************************************/
339 /*************************************************************************/
342 /* documentation is in ftcache.h */
344 FT_EXPORT_DEF( FT_Error
)
345 FTC_Manager_New( FT_Library library
,
349 FTC_Face_Requester requester
,
351 FTC_Manager
*amanager
)
355 FTC_Manager manager
= 0;
359 return FTC_Err_Invalid_Library_Handle
;
361 memory
= library
->memory
;
363 if ( FT_NEW( manager
) )
366 if ( max_faces
== 0 )
367 max_faces
= FTC_MAX_FACES_DEFAULT
;
369 if ( max_sizes
== 0 )
370 max_sizes
= FTC_MAX_SIZES_DEFAULT
;
372 if ( max_bytes
== 0 )
373 max_bytes
= FTC_MAX_BYTES_DEFAULT
;
375 manager
->library
= library
;
376 manager
->memory
= memory
;
377 manager
->max_weight
= max_bytes
;
379 manager
->request_face
= requester
;
380 manager
->request_data
= req_data
;
382 FTC_MruList_Init( &manager
->faces
,
383 &ftc_face_list_class
,
388 FTC_MruList_Init( &manager
->sizes
,
389 &ftc_size_list_class
,
401 /* documentation is in ftcache.h */
403 FT_EXPORT_DEF( void )
404 FTC_Manager_Done( FTC_Manager manager
)
410 if ( !manager
|| !manager
->library
)
413 memory
= manager
->memory
;
415 /* now discard all caches */
416 for (idx
= manager
->num_caches
; idx
-- > 0; )
418 FTC_Cache cache
= manager
->caches
[idx
];
423 cache
->clazz
.cache_done( cache
);
425 manager
->caches
[idx
] = NULL
;
428 manager
->num_caches
= 0;
430 /* discard faces and sizes */
431 FTC_MruList_Done( &manager
->sizes
);
432 FTC_MruList_Done( &manager
->faces
);
434 manager
->library
= NULL
;
435 manager
->memory
= NULL
;
441 /* documentation is in ftcache.h */
443 FT_EXPORT_DEF( void )
444 FTC_Manager_Reset( FTC_Manager manager
)
448 FTC_MruList_Reset( &manager
->sizes
);
449 FTC_MruList_Reset( &manager
->faces
);
451 /* XXX: FIXME: flush the caches? */
455 #ifdef FT_DEBUG_ERROR
458 FTC_Manager_Check( FTC_Manager manager
)
460 FTC_Node node
, first
;
463 first
= manager
->nodes_list
;
465 /* check node weights */
475 FTC_Cache cache
= manager
->caches
[node
->cache_index
];
478 if ( (FT_UInt
)node
->cache_index
>= manager
->num_caches
)
479 FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
480 node
->cache_index
));
482 weight
+= cache
->clazz
.node_weight( node
, cache
);
484 node
= FTC_NODE__NEXT( node
);
486 } while ( node
!= first
);
488 if ( weight
!= manager
->cur_weight
)
489 FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
490 manager
->cur_weight
, weight
));
493 /* check circular list */
503 node
= FTC_NODE__NEXT( node
);
505 } while ( node
!= first
);
507 if ( count
!= manager
->num_nodes
)
509 "FTC_Manager_Check: invalid cache node count %d instead of %d\n",
510 manager
->num_nodes
, count
));
514 #endif /* FT_DEBUG_ERROR */
517 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
518 /* that are not referenced anymore in order to limit the total */
519 /* memory used by the cache. */
521 /* documentation is in ftcmanag.h */
524 FTC_Manager_Compress( FTC_Manager manager
)
526 FTC_Node node
, first
;
532 first
= manager
->nodes_list
;
534 #ifdef FT_DEBUG_ERROR
535 FTC_Manager_Check( manager
);
537 FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
538 manager
->cur_weight
, manager
->max_weight
,
539 manager
->num_nodes
));
542 if ( manager
->cur_weight
< manager
->max_weight
|| first
== NULL
)
545 /* go to last node -- it's a circular list */
546 node
= FTC_NODE__PREV( first
);
552 prev
= ( node
== first
) ? NULL
: FTC_NODE__PREV( node
);
554 if ( node
->ref_count
<= 0 )
555 ftc_node_destroy( node
, manager
);
559 } while ( node
&& manager
->cur_weight
> manager
->max_weight
);
563 /* documentation is in ftcmanag.h */
565 FT_LOCAL_DEF( FT_Error
)
566 FTC_Manager_RegisterCache( FTC_Manager manager
,
567 FTC_CacheClass clazz
,
570 FT_Error error
= FTC_Err_Invalid_Argument
;
571 FTC_Cache cache
= NULL
;
574 if ( manager
&& clazz
&& acache
)
576 FT_Memory memory
= manager
->memory
;
579 if ( manager
->num_caches
>= FTC_MAX_CACHES
)
581 error
= FTC_Err_Too_Many_Caches
;
582 FT_ERROR(( "%s: too many registered caches\n",
583 "FTC_Manager_Register_Cache" ));
587 if ( !FT_ALLOC( cache
, clazz
->cache_size
) )
589 cache
->manager
= manager
;
590 cache
->memory
= memory
;
591 cache
->clazz
= clazz
[0];
592 cache
->org_class
= clazz
;
594 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
595 /* IF IT IS NOT SET CORRECTLY */
596 cache
->index
= manager
->num_caches
;
598 error
= clazz
->cache_init( cache
);
601 clazz
->cache_done( cache
);
606 manager
->caches
[manager
->num_caches
++] = cache
;
616 FT_LOCAL_DEF( FT_UInt
)
617 FTC_Manager_FlushN( FTC_Manager manager
,
620 FTC_Node first
= manager
->nodes_list
;
625 /* try to remove `count' nodes from the list */
626 if ( first
== NULL
) /* empty list! */
629 /* go to last node - it's a circular list */
630 node
= FTC_NODE__PREV(first
);
631 for ( result
= 0; result
< count
; )
633 FTC_Node prev
= FTC_NODE__PREV( node
);
636 /* don't touch locked nodes */
637 if ( node
->ref_count
<= 0 )
639 ftc_node_destroy( node
, manager
);
652 /* documentation is in ftcache.h */
654 FT_EXPORT_DEF( void )
655 FTC_Manager_RemoveFaceID( FTC_Manager manager
,
660 /* this will remove all FTC_SizeNode that correspond to
661 * the face_id as well
663 FTC_MruList_RemoveSelection( &manager
->faces
, NULL
, face_id
);
665 for ( nn
= 0; nn
< manager
->num_caches
; nn
++ )
666 FTC_Cache_RemoveFaceID( manager
->caches
[nn
], face_id
);
670 /* documentation is in ftcache.h */
672 FT_EXPORT_DEF( void )
673 FTC_Node_Unref( FTC_Node node
,
674 FTC_Manager manager
)
676 if ( node
&& (FT_UInt
)node
->cache_index
< manager
->num_caches
)
681 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
683 FT_EXPORT_DEF( FT_Error
)
684 FTC_Manager_Lookup_Face( FTC_Manager manager
,
688 return FTC_Manager_LookupFace( manager
, face_id
, aface
);
692 FT_EXPORT( FT_Error
)
693 FTC_Manager_Lookup_Size( FTC_Manager manager
,
698 FTC_ScalerRec scaler
;
704 scaler
.face_id
= font
->face_id
;
705 scaler
.width
= font
->pix_width
;
706 scaler
.height
= font
->pix_height
;
711 error
= FTC_Manager_LookupSize( manager
, &scaler
, &size
);
729 #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */