1
/***************************************************************************/
5
/* FreeType Cache Manager (body). */
7
/* Copyright 2000-2001, 2002 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
/***************************************************************************/
21
#include FT_CACHE_MANAGER_H
22
#include FT_CACHE_INTERNAL_LRU_H
23
#include FT_INTERNAL_OBJECTS_H
24
#include FT_INTERNAL_DEBUG_H
31
#define FT_COMPONENT trace_cache
33
#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
36
/*************************************************************************/
37
/*************************************************************************/
39
/***** FACE LRU IMPLEMENTATION *****/
41
/*************************************************************************/
42
/*************************************************************************/
44
typedef struct FTC_FaceNodeRec_* FTC_FaceNode;
45
typedef struct FTC_SizeNodeRec_* FTC_SizeNode;
48
typedef struct FTC_FaceNodeRec_
56
typedef struct FTC_SizeNodeRec_
64
FT_CALLBACK_DEF( FT_Error )
65
ftc_face_node_init( FTC_FaceNode node,
72
error = manager->request_face( face_id,
74
manager->request_data,
78
/* destroy initial size object; it will be re-created later */
79
if ( node->face->size )
80
FT_Done_Size( node->face->size );
87
/* helper function for ftc_face_node_done() */
88
FT_CALLBACK_DEF( FT_Bool )
89
ftc_size_node_select( FTC_SizeNode node,
92
return FT_BOOL( node->size->face == face );
96
FT_CALLBACK_DEF( void )
97
ftc_face_node_done( FTC_FaceNode node,
100
FT_Face face = node->face;
103
/* we must begin by removing all sizes for the target face */
104
/* from the manager's list */
105
FT_LruList_Remove_Selection( manager->sizes_list,
106
(FT_LruNode_SelectFunc)ftc_size_node_select,
109
/* all right, we can discard the face now */
110
FT_Done_Face( face );
115
FT_CALLBACK_TABLE_DEF
116
const FT_LruList_ClassRec ftc_face_list_class =
118
sizeof ( FT_LruListRec ),
119
(FT_LruList_InitFunc)0,
120
(FT_LruList_DoneFunc)0,
122
sizeof ( FTC_FaceNodeRec ),
123
(FT_LruNode_InitFunc) ftc_face_node_init,
124
(FT_LruNode_DoneFunc) ftc_face_node_done,
125
(FT_LruNode_FlushFunc) 0, /* no flushing needed */
126
(FT_LruNode_CompareFunc)0, /* direct comparison of FTC_FaceID handles */
130
/* documentation is in ftcache.h */
132
FT_EXPORT_DEF( FT_Error )
133
FTC_Manager_Lookup_Face( FTC_Manager manager,
142
return FTC_Err_Bad_Argument;
147
return FTC_Err_Invalid_Cache_Handle;
149
error = FT_LruList_Lookup( manager->faces_list,
151
(FT_LruNode*)&node );
159
/*************************************************************************/
160
/*************************************************************************/
162
/***** SIZES LRU IMPLEMENTATION *****/
164
/*************************************************************************/
165
/*************************************************************************/
168
typedef struct FTC_SizeQueryRec_
174
} FTC_SizeQueryRec, *FTC_SizeQuery;
177
FT_CALLBACK_DEF( FT_Error )
178
ftc_size_node_init( FTC_SizeNode node,
179
FTC_SizeQuery query )
181
FT_Face face = query->face;
187
error = FT_New_Size( face, &size );
190
FT_Activate_Size( size );
191
error = FT_Set_Pixel_Sizes( query->face,
195
FT_Done_Size( size );
203
FT_CALLBACK_DEF( void )
204
ftc_size_node_done( FTC_SizeNode node )
208
FT_Done_Size( node->size );
214
FT_CALLBACK_DEF( FT_Error )
215
ftc_size_node_flush( FTC_SizeNode node,
216
FTC_SizeQuery query )
218
FT_Size size = node->size;
222
if ( size->face == query->face )
224
FT_Activate_Size( size );
225
error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
228
FT_Done_Size( size );
234
FT_Done_Size( size );
237
error = ftc_size_node_init( node, query );
243
FT_CALLBACK_DEF( FT_Bool )
244
ftc_size_node_compare( FTC_SizeNode node,
245
FTC_SizeQuery query )
247
FT_Size size = node->size;
250
return FT_BOOL( size->face == query->face &&
251
(FT_UInt)size->metrics.x_ppem == query->width &&
252
(FT_UInt)size->metrics.y_ppem == query->height );
256
FT_CALLBACK_TABLE_DEF
257
const FT_LruList_ClassRec ftc_size_list_class =
259
sizeof ( FT_LruListRec ),
260
(FT_LruList_InitFunc)0,
261
(FT_LruList_DoneFunc)0,
263
sizeof ( FTC_SizeNodeRec ),
264
(FT_LruNode_InitFunc) ftc_size_node_init,
265
(FT_LruNode_DoneFunc) ftc_size_node_done,
266
(FT_LruNode_FlushFunc) ftc_size_node_flush,
267
(FT_LruNode_CompareFunc)ftc_size_node_compare
271
/* documentation is in ftcache.h */
273
FT_EXPORT_DEF( FT_Error )
274
FTC_Manager_Lookup_Size( FTC_Manager manager,
282
/* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
289
error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
292
FTC_SizeQueryRec query;
297
query.width = font->pix_width;
298
query.height = font->pix_height;
300
error = FT_LruList_Lookup( manager->sizes_list,
302
(FT_LruNode*)&node );
305
/* select the size as the current one for this face */
306
FT_Activate_Size( node->size );
317
/*************************************************************************/
318
/*************************************************************************/
320
/***** SET TABLE MANAGEMENT *****/
322
/*************************************************************************/
323
/*************************************************************************/
326
ftc_family_table_init( FTC_FamilyTable table )
330
table->entries = NULL;
331
table->free = FTC_FAMILY_ENTRY_NONE;
336
ftc_family_table_done( FTC_FamilyTable table,
339
FT_FREE( table->entries );
346
FT_EXPORT_DEF( FT_Error )
347
ftc_family_table_alloc( FTC_FamilyTable table,
349
FTC_FamilyEntry *aentry )
351
FTC_FamilyEntry entry;
355
/* re-allocate table size when needed */
356
if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
358
FT_UInt old_size = table->size;
359
FT_UInt new_size, idx;
366
new_size = old_size * 2;
368
/* check for (unlikely) overflow */
369
if ( new_size < old_size )
373
if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
376
table->size = new_size;
378
entry = table->entries + old_size;
379
table->free = old_size;
381
for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
383
entry->link = idx + 1;
387
entry->link = FTC_FAMILY_ENTRY_NONE;
391
if ( table->free != FTC_FAMILY_ENTRY_NONE )
393
entry = table->entries + table->free;
394
table->free = entry->link;
396
else if ( table->count < table->size )
398
entry = table->entries + table->count++;
402
FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
403
return FTC_Err_Invalid_Argument;
406
entry->link = FTC_FAMILY_ENTRY_NONE;
414
FT_EXPORT_DEF( void )
415
ftc_family_table_free( FTC_FamilyTable table,
418
/* simply add it to the linked list of free entries */
419
if ( idx < table->count )
421
FTC_FamilyEntry entry = table->entries + idx;
424
if ( entry->link != FTC_FAMILY_ENTRY_NONE )
425
FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
428
entry->link = table->free;
429
table->free = entry->index;
436
/*************************************************************************/
437
/*************************************************************************/
439
/***** CACHE MANAGER ROUTINES *****/
441
/*************************************************************************/
442
/*************************************************************************/
445
/* documentation is in ftcache.h */
447
FT_EXPORT_DEF( FT_Error )
448
FTC_Manager_New( FT_Library library,
452
FTC_Face_Requester requester,
454
FTC_Manager *amanager )
458
FTC_Manager manager = 0;
462
return FTC_Err_Invalid_Library_Handle;
464
memory = library->memory;
466
if ( FT_NEW( manager ) )
469
if ( max_faces == 0 )
470
max_faces = FTC_MAX_FACES_DEFAULT;
472
if ( max_sizes == 0 )
473
max_sizes = FTC_MAX_SIZES_DEFAULT;
475
if ( max_bytes == 0 )
476
max_bytes = FTC_MAX_BYTES_DEFAULT;
478
error = FT_LruList_New( &ftc_face_list_class,
482
&manager->faces_list );
486
error = FT_LruList_New( &ftc_size_list_class,
490
&manager->sizes_list );
494
manager->library = library;
495
manager->max_weight = max_bytes;
496
manager->cur_weight = 0;
498
manager->request_face = requester;
499
manager->request_data = req_data;
501
ftc_family_table_init( &manager->families );
506
if ( error && manager )
508
FT_LruList_Destroy( manager->faces_list );
509
FT_LruList_Destroy( manager->sizes_list );
517
/* documentation is in ftcache.h */
519
FT_EXPORT_DEF( void )
520
FTC_Manager_Done( FTC_Manager manager )
526
if ( !manager || !manager->library )
529
memory = manager->library->memory;
531
/* now discard all caches */
532
for (idx = 0; idx < FTC_MAX_CACHES; idx++ )
534
FTC_Cache cache = manager->caches[idx];
539
cache->clazz->cache_done( cache );
541
manager->caches[idx] = 0;
545
/* discard families table */
546
ftc_family_table_done( &manager->families, memory );
548
/* discard faces and sizes */
549
FT_LruList_Destroy( manager->faces_list );
550
manager->faces_list = 0;
552
FT_LruList_Destroy( manager->sizes_list );
553
manager->sizes_list = 0;
559
/* documentation is in ftcache.h */
561
FT_EXPORT_DEF( void )
562
FTC_Manager_Reset( FTC_Manager manager )
566
FT_LruList_Reset( manager->sizes_list );
567
FT_LruList_Reset( manager->faces_list );
569
/* XXX: FIXME: flush the caches? */
573
#ifdef FT_DEBUG_ERROR
575
FT_EXPORT_DEF( void )
576
FTC_Manager_Check( FTC_Manager manager )
578
FTC_Node node, first;
581
first = manager->nodes_list;
583
/* check node weights */
593
FTC_FamilyEntry entry = manager->families.entries + node->fam_index;
596
if ( (FT_UInt)node->fam_index >= manager->families.count ||
597
entry->link != FTC_FAMILY_ENTRY_NONE )
598
FT_ERROR(( "FTC_Manager_Check: invalid node (family index = %ld\n",
602
cache = entry->cache;
603
weight += cache->clazz->node_weight( node, cache );
606
node = node->mru_next;
608
} while ( node != first );
610
if ( weight != manager->cur_weight )
611
FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
612
manager->cur_weight, weight ));
615
/* check circular list */
625
node = node->mru_next;
627
} while ( node != first );
629
if ( count != manager->num_nodes )
631
"FTC_Manager_Check: invalid cache node count %d instead of %d\n",
632
manager->num_nodes, count ));
636
#endif /* FT_DEBUG_ERROR */
639
/* `Compress' the manager's data, i.e., get rid of old cache nodes */
640
/* that are not referenced anymore in order to limit the total */
641
/* memory used by the cache. */
643
/* documentation is in ftcmanag.h */
645
FT_EXPORT_DEF( void )
646
FTC_Manager_Compress( FTC_Manager manager )
648
FTC_Node node, first;
654
first = manager->nodes_list;
656
#ifdef FT_DEBUG_ERROR
657
FTC_Manager_Check( manager );
659
FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
660
manager->cur_weight, manager->max_weight,
661
manager->num_nodes ));
664
if ( manager->cur_weight < manager->max_weight || first == NULL )
667
/* go to last node - it's a circular list */
668
node = first->mru_prev;
671
FTC_Node prev = node->mru_prev;
674
prev = ( node == first ) ? NULL : node->mru_prev;
676
if ( node->ref_count <= 0 )
677
ftc_node_destroy( node, manager );
681
} while ( node && manager->cur_weight > manager->max_weight );
685
/* documentation is in ftcmanag.h */
687
FT_EXPORT_DEF( FT_Error )
688
FTC_Manager_Register_Cache( FTC_Manager manager,
689
FTC_Cache_Class clazz,
692
FT_Error error = FTC_Err_Invalid_Argument;
693
FTC_Cache cache = NULL;
696
if ( manager && clazz && acache )
698
FT_Memory memory = manager->library->memory;
702
/* check for an empty cache slot in the manager's table */
703
for ( idx = 0; idx < FTC_MAX_CACHES; idx++ )
705
if ( manager->caches[idx] == 0 )
709
/* return an error if there are too many registered caches */
710
if ( idx >= FTC_MAX_CACHES )
712
error = FTC_Err_Too_Many_Caches;
713
FT_ERROR(( "FTC_Manager_Register_Cache:" ));
714
FT_ERROR(( " too many registered caches\n" ));
718
if ( !FT_ALLOC( cache, clazz->cache_size ) )
720
cache->manager = manager;
721
cache->memory = memory;
722
cache->clazz = clazz;
724
/* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
725
/* IF IT IS NOT SET CORRECTLY */
726
cache->cache_index = idx;
728
if ( clazz->cache_init )
730
error = clazz->cache_init( cache );
733
if ( clazz->cache_done )
734
clazz->cache_done( cache );
741
manager->caches[idx] = cache;
751
/* documentation is in ftcmanag.h */
753
FT_EXPORT_DEF( void )
754
FTC_Node_Unref( FTC_Node node,
755
FTC_Manager manager )
757
if ( node && (FT_UInt)node->fam_index < manager->families.count &&
758
manager->families.entries[node->fam_index].cache )