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
),
159 ftc_size_node_compare
,
166 /* helper function used by ftc_face_node_done */
168 ftc_size_node_compare_faceid( FTC_MruNode ftcnode
,
169 FT_Pointer ftcface_id
)
171 FTC_SizeNode node
= (FTC_SizeNode
)ftcnode
;
172 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
175 return FT_BOOL( node
->scaler
.face_id
== face_id
);
179 /* documentation is in ftcache.h */
181 FT_EXPORT_DEF( FT_Error
)
182 FTC_Manager_LookupSize( FTC_Manager manager
,
190 if ( !asize
|| !scaler
)
191 return FT_THROW( Invalid_Argument
);
196 return FT_THROW( Invalid_Cache_Handle
);
200 FTC_MRULIST_LOOKUP_CMP( &manager
->sizes
, scaler
, ftc_size_node_compare
,
204 error
= FTC_MruList_Lookup( &manager
->sizes
, scaler
, &mrunode
);
208 *asize
= FTC_SIZE_NODE( mrunode
)->size
;
214 /*************************************************************************/
215 /*************************************************************************/
217 /***** FACE MRU IMPLEMENTATION *****/
219 /*************************************************************************/
220 /*************************************************************************/
222 typedef struct FTC_FaceNodeRec_
228 } FTC_FaceNodeRec
, *FTC_FaceNode
;
230 #define FTC_FACE_NODE( x ) ( ( FTC_FaceNode )( x ) )
233 FT_CALLBACK_DEF( FT_Error
)
234 ftc_face_node_init( FTC_MruNode ftcnode
,
235 FT_Pointer ftcface_id
,
236 FT_Pointer ftcmanager
)
238 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
239 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
240 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
244 node
->face_id
= face_id
;
246 error
= manager
->request_face( face_id
,
248 manager
->request_data
,
252 /* destroy initial size object; it will be re-created later */
253 if ( node
->face
->size
)
254 FT_Done_Size( node
->face
->size
);
261 FT_CALLBACK_DEF( void )
262 ftc_face_node_done( FTC_MruNode ftcnode
,
263 FT_Pointer ftcmanager
)
265 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
266 FTC_Manager manager
= (FTC_Manager
)ftcmanager
;
269 /* we must begin by removing all scalers for the target face */
270 /* from the manager's list */
271 FTC_MruList_RemoveSelection( &manager
->sizes
,
272 ftc_size_node_compare_faceid
,
275 /* all right, we can discard the face now */
276 FT_Done_Face( node
->face
);
278 node
->face_id
= NULL
;
282 FT_CALLBACK_DEF( FT_Bool
)
283 ftc_face_node_compare( FTC_MruNode ftcnode
,
284 FT_Pointer ftcface_id
)
286 FTC_FaceNode node
= (FTC_FaceNode
)ftcnode
;
287 FTC_FaceID face_id
= (FTC_FaceID
)ftcface_id
;
290 return FT_BOOL( node
->face_id
== face_id
);
295 const FTC_MruListClassRec ftc_face_list_class
=
297 sizeof ( FTC_FaceNodeRec
),
299 ftc_face_node_compare
,
301 0, /* FTC_MruNode_ResetFunc */
306 /* documentation is in ftcache.h */
308 FT_EXPORT_DEF( FT_Error
)
309 FTC_Manager_LookupFace( FTC_Manager manager
,
318 return FT_THROW( Invalid_Argument
);
323 return FT_THROW( Invalid_Cache_Handle
);
325 /* we break encapsulation for the sake of speed */
328 FTC_MRULIST_LOOKUP_CMP( &manager
->faces
, face_id
, ftc_face_node_compare
,
332 error
= FTC_MruList_Lookup( &manager
->faces
, face_id
, &mrunode
);
336 *aface
= FTC_FACE_NODE( mrunode
)->face
;
342 /*************************************************************************/
343 /*************************************************************************/
345 /***** CACHE MANAGER ROUTINES *****/
347 /*************************************************************************/
348 /*************************************************************************/
351 /* documentation is in ftcache.h */
353 FT_EXPORT_DEF( FT_Error
)
354 FTC_Manager_New( FT_Library library
,
358 FTC_Face_Requester requester
,
360 FTC_Manager
*amanager
)
364 FTC_Manager manager
= 0;
368 return FT_THROW( Invalid_Library_Handle
);
370 if ( !amanager
|| !requester
)
371 return FT_THROW( Invalid_Argument
);
373 memory
= library
->memory
;
375 if ( FT_NEW( manager
) )
378 if ( max_faces
== 0 )
379 max_faces
= FTC_MAX_FACES_DEFAULT
;
381 if ( max_sizes
== 0 )
382 max_sizes
= FTC_MAX_SIZES_DEFAULT
;
384 if ( max_bytes
== 0 )
385 max_bytes
= FTC_MAX_BYTES_DEFAULT
;
387 manager
->library
= library
;
388 manager
->memory
= memory
;
389 manager
->max_weight
= max_bytes
;
391 manager
->request_face
= requester
;
392 manager
->request_data
= req_data
;
394 FTC_MruList_Init( &manager
->faces
,
395 &ftc_face_list_class
,
400 FTC_MruList_Init( &manager
->sizes
,
401 &ftc_size_list_class
,
413 /* documentation is in ftcache.h */
415 FT_EXPORT_DEF( void )
416 FTC_Manager_Done( FTC_Manager manager
)
422 if ( !manager
|| !manager
->library
)
425 memory
= manager
->memory
;
427 /* now discard all caches */
428 for (idx
= manager
->num_caches
; idx
-- > 0; )
430 FTC_Cache cache
= manager
->caches
[idx
];
435 cache
->clazz
.cache_done( cache
);
437 manager
->caches
[idx
] = NULL
;
440 manager
->num_caches
= 0;
442 /* discard faces and sizes */
443 FTC_MruList_Done( &manager
->sizes
);
444 FTC_MruList_Done( &manager
->faces
);
446 manager
->library
= NULL
;
447 manager
->memory
= NULL
;
453 /* documentation is in ftcache.h */
455 FT_EXPORT_DEF( void )
456 FTC_Manager_Reset( FTC_Manager manager
)
461 FTC_MruList_Reset( &manager
->sizes
);
462 FTC_MruList_Reset( &manager
->faces
);
464 FTC_Manager_FlushN( manager
, manager
->num_nodes
);
468 #ifdef FT_DEBUG_ERROR
471 FTC_Manager_Check( FTC_Manager manager
)
473 FTC_Node node
, first
;
476 first
= manager
->nodes_list
;
478 /* check node weights */
481 FT_Offset weight
= 0;
488 FTC_Cache cache
= manager
->caches
[node
->cache_index
];
491 if ( (FT_UInt
)node
->cache_index
>= manager
->num_caches
)
492 FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
493 node
->cache_index
));
495 weight
+= cache
->clazz
.node_weight( node
, cache
);
497 node
= FTC_NODE_NEXT( node
);
499 } while ( node
!= first
);
501 if ( weight
!= manager
->cur_weight
)
502 FT_TRACE0(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
503 manager
->cur_weight
, weight
));
506 /* check circular list */
516 node
= FTC_NODE_NEXT( node
);
518 } while ( node
!= first
);
520 if ( count
!= manager
->num_nodes
)
521 FT_TRACE0(( "FTC_Manager_Check:"
522 " invalid cache node count %d instead of %d\n",
523 manager
->num_nodes
, count
));
527 #endif /* FT_DEBUG_ERROR */
530 /* `Compress' the manager's data, i.e., get rid of old cache nodes */
531 /* that are not referenced anymore in order to limit the total */
532 /* memory used by the cache. */
534 /* documentation is in ftcmanag.h */
537 FTC_Manager_Compress( FTC_Manager manager
)
539 FTC_Node node
, first
;
545 first
= manager
->nodes_list
;
547 #ifdef FT_DEBUG_ERROR
548 FTC_Manager_Check( manager
);
550 FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
551 manager
->cur_weight
, manager
->max_weight
,
552 manager
->num_nodes
));
555 if ( manager
->cur_weight
< manager
->max_weight
|| first
== NULL
)
558 /* go to last node -- it's a circular list */
559 node
= FTC_NODE_PREV( first
);
565 prev
= ( node
== first
) ? NULL
: FTC_NODE_PREV( node
);
567 if ( node
->ref_count
<= 0 )
568 ftc_node_destroy( node
, manager
);
572 } while ( node
&& manager
->cur_weight
> manager
->max_weight
);
576 /* documentation is in ftcmanag.h */
578 FT_LOCAL_DEF( FT_Error
)
579 FTC_Manager_RegisterCache( FTC_Manager manager
,
580 FTC_CacheClass clazz
,
583 FT_Error error
= FT_ERR( Invalid_Argument
);
584 FTC_Cache cache
= NULL
;
587 if ( manager
&& clazz
&& acache
)
589 FT_Memory memory
= manager
->memory
;
592 if ( manager
->num_caches
>= FTC_MAX_CACHES
)
594 error
= FT_THROW( Too_Many_Caches
);
595 FT_ERROR(( "FTC_Manager_RegisterCache:"
596 " too many registered caches\n" ));
600 if ( !FT_ALLOC( cache
, clazz
->cache_size
) )
602 cache
->manager
= manager
;
603 cache
->memory
= memory
;
604 cache
->clazz
= clazz
[0];
605 cache
->org_class
= clazz
;
607 /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
608 /* IF IT IS NOT SET CORRECTLY */
609 cache
->index
= manager
->num_caches
;
611 error
= clazz
->cache_init( cache
);
614 clazz
->cache_done( cache
);
619 manager
->caches
[manager
->num_caches
++] = cache
;
630 FT_LOCAL_DEF( FT_UInt
)
631 FTC_Manager_FlushN( FTC_Manager manager
,
634 FTC_Node first
= manager
->nodes_list
;
639 /* try to remove `count' nodes from the list */
640 if ( first
== NULL
) /* empty list! */
643 /* go to last node - it's a circular list */
644 node
= FTC_NODE_PREV(first
);
645 for ( result
= 0; result
< count
; )
647 FTC_Node prev
= FTC_NODE_PREV( node
);
650 /* don't touch locked nodes */
651 if ( node
->ref_count
<= 0 )
653 ftc_node_destroy( node
, manager
);
666 /* documentation is in ftcache.h */
668 FT_EXPORT_DEF( void )
669 FTC_Manager_RemoveFaceID( FTC_Manager manager
,
678 /* this will remove all FTC_SizeNode that correspond to
679 * the face_id as well
681 FTC_MruList_RemoveSelection( &manager
->faces
,
682 ftc_face_node_compare
,
685 for ( nn
= 0; nn
< manager
->num_caches
; nn
++ )
686 FTC_Cache_RemoveFaceID( manager
->caches
[nn
], face_id
);
690 /* documentation is in ftcache.h */
692 FT_EXPORT_DEF( void )
693 FTC_Node_Unref( FTC_Node node
,
694 FTC_Manager manager
)
698 (FT_UInt
)node
->cache_index
< manager
->num_caches
)