1 /***************************************************************************/
5 /* FreeType Cache Manager (body). */
7 /* Copyright 2000-2016 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
39 ftc_scaler_lookup_size( FTC_Manager manager
,
48 error
= FTC_Manager_LookupFace( manager
, scaler
->face_id
, &face
);
52 error
= FT_New_Size( face
, &size
);
56 FT_Activate_Size( size
);
59 error
= FT_Set_Pixel_Sizes( face
, scaler
->width
, scaler
->height
);
61 error
= FT_Set_Char_Size( face
,
62 (FT_F26Dot6
)scaler
->width
,
63 (FT_F26Dot6
)scaler
->height
,
78 typedef struct FTC_SizeNodeRec_
84 } FTC_SizeNodeRec
, *FTC_SizeNode
;
86 #define FTC_SIZE_NODE( x ) ( (FTC_SizeNode)( x ) )
89 FT_CALLBACK_DEF( void )
90 ftc_size_node_done( FTC_MruNode ftcnode
,
93 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
94 FT_Size size
= node
->size
;
103 FT_CALLBACK_DEF( FT_Bool
)
104 ftc_size_node_compare( FTC_MruNode ftcnode
,
105 FT_Pointer ftcscaler
)
107 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
108 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
109 FTC_Scaler scaler0
= &node
->scaler
;
112 if ( FTC_SCALER_COMPARE( scaler0
, scaler
) )
114 FT_Activate_Size( node
->size
);
121 FT_CALLBACK_DEF( FT_Error
)
122 ftc_size_node_init( FTC_MruNode ftcnode
,
123 FT_Pointer ftcscaler
,
124 FT_Pointer ftcmanager
)
126 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
127 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
128 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
131 node
->scaler
= scaler
[0];
133 return ftc_scaler_lookup_size( manager
, scaler
, &node
->size
);
137 FT_CALLBACK_DEF( FT_Error
)
138 ftc_size_node_reset( FTC_MruNode ftcnode
,
139 FT_Pointer ftcscaler
,
140 FT_Pointer ftcmanager
)
142 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
143 FTC_Scaler scaler
= (FTC_Scaler
)ftcscaler
;
144 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
147 FT_Done_Size( node
->size
);
149 node
->scaler
= scaler
[0];
151 return ftc_scaler_lookup_size( manager
, scaler
, &node
->size
);
156 const FTC_MruListClassRec ftc_size_list_class
=
158 sizeof ( FTC_SizeNodeRec
),
160 ftc_size_node_compare
, /* FTC_MruNode_CompareFunc node_compare */
161 ftc_size_node_init
, /* FTC_MruNode_InitFunc node_init */
162 ftc_size_node_reset
, /* FTC_MruNode_ResetFunc node_reset */
163 ftc_size_node_done
/* FTC_MruNode_DoneFunc node_done */
167 /* helper function used by ftc_face_node_done */
169 ftc_size_node_compare_faceid( FTC_MruNode ftcnode
,
170 FT_Pointer ftcface_id
)
172 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
173 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
176 return FT_BOOL( node
->scaler
.face_id
== face_id
);
180 /* documentation is in ftcache.h */
182 FT_EXPORT_DEF( FT_Error
)
183 FTC_Manager_LookupSize( FTC_Manager manager
,
191 if ( !asize
|| !scaler
)
192 return FT_THROW( Invalid_Argument
);
197 return FT_THROW( Invalid_Cache_Handle
);
201 FTC_MRULIST_LOOKUP_CMP( &manager
->sizes
, scaler
, ftc_size_node_compare
,
205 error
= FTC_MruList_Lookup( &manager
->sizes
, scaler
, &mrunode
);
209 *asize
= FTC_SIZE_NODE( mrunode
)->size
;
215 /*************************************************************************/
216 /*************************************************************************/
218 /***** FACE MRU IMPLEMENTATION *****/
220 /*************************************************************************/
221 /*************************************************************************/
223 typedef struct FTC_FaceNodeRec_
229 } FTC_FaceNodeRec
, *FTC_FaceNode
;
231 #define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
234 FT_CALLBACK_DEF( FT_Error
)
235 ftc_face_node_init( FTC_MruNode ftcnode
,
236 FT_Pointer ftcface_id
,
237 FT_Pointer ftcmanager
)
239 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
240 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
241 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
245 node
->face_id
= face_id
;
247 error
= manager
->request_face( face_id
,
249 manager
->request_data
,
253 /* destroy initial size object; it will be re-created later */
254 if ( node
->face
->size
)
255 FT_Done_Size( node
->face
->size
);
262 FT_CALLBACK_DEF( void )
263 ftc_face_node_done( FTC_MruNode ftcnode
,
264 FT_Pointer ftcmanager
)
266 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
267 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
270 /* we must begin by removing all scalers for the target face */
271 /* from the manager's list */
272 FTC_MruList_RemoveSelection( &manager
->sizes
,
273 ftc_size_node_compare_faceid
,
276 /* all right, we can discard the face now */
277 FT_Done_Face( node
->face
);
279 node
->face_id
= NULL
;
283 FT_CALLBACK_DEF( FT_Bool
)
284 ftc_face_node_compare( FTC_MruNode ftcnode
,
285 FT_Pointer ftcface_id
)
287 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
288 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
291 return FT_BOOL( node
->face_id
== face_id
);
296 const FTC_MruListClassRec ftc_face_list_class
=
298 sizeof ( FTC_FaceNodeRec
),
300 ftc_face_node_compare
, /* FTC_MruNode_CompareFunc node_compare */
301 ftc_face_node_init
, /* FTC_MruNode_InitFunc node_init */
302 NULL
, /* FTC_MruNode_ResetFunc node_reset */
303 ftc_face_node_done
/* FTC_MruNode_DoneFunc node_done */
307 /* documentation is in ftcache.h */
309 FT_EXPORT_DEF( FT_Error
)
310 FTC_Manager_LookupFace( FTC_Manager manager
,
319 return FT_THROW( Invalid_Argument
);
324 return FT_THROW( Invalid_Cache_Handle
);
326 /* we break encapsulation for the sake of speed */
329 FTC_MRULIST_LOOKUP_CMP( &manager
->faces
, face_id
, ftc_face_node_compare
,
333 error
= FTC_MruList_Lookup( &manager
->faces
, face_id
, &mrunode
);
337 *aface
= FTC_FACE_NODE( mrunode
)->face
;
343 /*************************************************************************/
344 /*************************************************************************/
346 /***** CACHE MANAGER ROUTINES *****/
348 /*************************************************************************/
349 /*************************************************************************/
352 /* documentation is in ftcache.h */
354 FT_EXPORT_DEF( FT_Error
)
355 FTC_Manager_New( FT_Library library
,
359 FTC_Face_Requester requester
,
361 FTC_Manager
*amanager
)
365 FTC_Manager manager
= 0;
369 return FT_THROW( Invalid_Library_Handle
);
371 if ( !amanager
|| !requester
)
372 return FT_THROW( Invalid_Argument
);
374 memory
= library
->memory
;
376 if ( FT_NEW( manager
) )
379 if ( max_faces
== 0 )
380 max_faces
= FTC_MAX_FACES_DEFAULT
;
382 if ( max_sizes
== 0 )
383 max_sizes
= FTC_MAX_SIZES_DEFAULT
;
385 if ( max_bytes
== 0 )
386 max_bytes
= FTC_MAX_BYTES_DEFAULT
;
388 manager
->library
= library
;
389 manager
->memory
= memory
;
390 manager
->max_weight
= max_bytes
;
392 manager
->request_face
= requester
;
393 manager
->request_data
= req_data
;
395 FTC_MruList_Init( &manager
->faces
,
396 &ftc_face_list_class
,
401 FTC_MruList_Init( &manager
->sizes
,
402 &ftc_size_list_class
,
414 /* documentation is in ftcache.h */
416 FT_EXPORT_DEF( void )
417 FTC_Manager_Done( FTC_Manager manager
)
423 if ( !manager
|| !manager
->library
)
426 memory
= manager
->memory
;
428 /* now discard all caches */
429 for (idx
= manager
->num_caches
; idx
-- > 0; )
431 FTC_Cache cache
= manager
->caches
[idx
];
436 cache
->clazz
.cache_done( cache
);
438 manager
->caches
[idx
] = NULL
;
441 manager
->num_caches
= 0;
443 /* discard faces and sizes */
444 FTC_MruList_Done( &manager
->sizes
);
445 FTC_MruList_Done( &manager
->faces
);
447 manager
->library
= NULL
;
448 manager
->memory
= NULL
;
454 /* documentation is in ftcache.h */
456 FT_EXPORT_DEF( void )
457 FTC_Manager_Reset( FTC_Manager manager
)
462 FTC_MruList_Reset( &manager
->sizes
);
463 FTC_MruList_Reset( &manager
->faces
);
465 FTC_Manager_FlushN( manager
, manager
->num_nodes
);
469 #ifdef FT_DEBUG_ERROR
472 FTC_Manager_Check( FTC_Manager manager
)
474 FTC_Node node
, first
;
477 first
= manager
->nodes_list
;
479 /* check node weights */
482 FT_Offset weight
= 0;
489 FTC_Cache cache
= manager
->caches
[node
->cache_index
];
492 if ( (FT_UInt
)node
->cache_index
>= manager
->num_caches
)
493 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
494 node
->cache_index
));
496 weight
+= cache
->clazz
.node_weight( node
, cache
);
498 node
= FTC_NODE_NEXT( node
);
500 } while ( node
!= first
);
502 if ( weight
!= manager
->cur_weight
)
503 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
504 manager
->cur_weight
, weight
));
507 /* check circular list */
517 node
= FTC_NODE_NEXT( node
);
519 } while ( node
!= first
);
521 if ( count
!= manager
->num_nodes
)
522 FT_TRACE0(( "FTC_Manager_Check:"
523 " invalid cache node count %d instead of %d\n",
524 manager
->num_nodes
, count
));
528 #endif /* FT_DEBUG_ERROR */
531 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
532 /* that are not referenced anymore in order to limit the total */
533 /* memory used by the cache. */
535 /* documentation is in ftcmanag.h */
538 FTC_Manager_Compress( FTC_Manager manager
)
540 FTC_Node node
, first
;
546 first
= manager
->nodes_list
;
548 #ifdef FT_DEBUG_ERROR
549 FTC_Manager_Check( manager
);
551 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
552 manager
->cur_weight
, manager
->max_weight
,
553 manager
->num_nodes
));
556 if ( manager
->cur_weight
< manager
->max_weight
|| !first
)
559 /* go to last node -- it's a circular list */
560 node
= FTC_NODE_PREV( first
);
566 prev
= ( node
== first
) ? NULL
: FTC_NODE_PREV( node
);
568 if ( node
->ref_count
<= 0 )
569 ftc_node_destroy( node
, manager
);
573 } while ( node
&& manager
->cur_weight
> manager
->max_weight
);
577 /* documentation is in ftcmanag.h */
579 FT_LOCAL_DEF( FT_Error
)
580 FTC_Manager_RegisterCache( FTC_Manager manager
,
581 FTC_CacheClass clazz
,
584 FT_Error error
= FT_ERR( Invalid_Argument
);
585 FTC_Cache cache
= NULL
;
588 if ( manager
&& clazz
&& acache
)
590 FT_Memory memory
= manager
->memory
;
593 if ( manager
->num_caches
>= FTC_MAX_CACHES
)
595 error
= FT_THROW( Too_Many_Caches
);
596 FT_ERROR(( "FTC_Manager_RegisterCache:"
597 " too many registered caches\n" ));
601 if ( !FT_ALLOC( cache
, clazz
->cache_size
) )
603 cache
->manager
= manager
;
604 cache
->memory
= memory
;
605 cache
->clazz
= clazz
[0];
606 cache
->org_class
= clazz
;
608 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
609 /* IF IT IS NOT SET CORRECTLY */
610 cache
->index
= manager
->num_caches
;
612 error
= clazz
->cache_init( cache
);
615 clazz
->cache_done( cache
);
620 manager
->caches
[manager
->num_caches
++] = cache
;
631 FT_LOCAL_DEF( FT_UInt
)
632 FTC_Manager_FlushN( FTC_Manager manager
,
635 FTC_Node first
= manager
->nodes_list
;
640 /* try to remove `count' nodes from the list */
641 if ( !first
) /* empty list! */
644 /* go to last node - it's a circular list */
645 node
= FTC_NODE_PREV(first
);
646 for ( result
= 0; result
< count
; )
648 FTC_Node prev
= FTC_NODE_PREV( node
);
651 /* don't touch locked nodes */
652 if ( node
->ref_count
<= 0 )
654 ftc_node_destroy( node
, manager
);
667 /* documentation is in ftcache.h */
669 FT_EXPORT_DEF( void )
670 FTC_Manager_RemoveFaceID( FTC_Manager manager
,
679 /* this will remove all FTC_SizeNode that correspond to
680 * the face_id as well
682 FTC_MruList_RemoveSelection( &manager
->faces
,
683 ftc_face_node_compare
,
686 for ( nn
= 0; nn
< manager
->num_caches
; nn
++ )
687 FTC_Cache_RemoveFaceID( manager
->caches
[nn
], face_id
);
691 /* documentation is in ftcache.h */
693 FT_EXPORT_DEF( void )
694 FTC_Node_Unref( FTC_Node node
,
695 FTC_Manager manager
)
699 (FT_UInt
)node
->cache_index
< manager
->num_caches
)