123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- /***************************************************************************/
- /* */
- /* ftcmanag.c */
- /* */
- /* FreeType Cache Manager (body). */
- /* */
- /* Copyright 2000-2001, 2002 by */
- /* David Turner, Robert Wilhelm, and Werner Lemberg. */
- /* */
- /* This file is part of the FreeType project, and may only be used, */
- /* modified, and distributed under the terms of the FreeType project */
- /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
- /* this file you indicate that you have read the license and */
- /* understand and accept it fully. */
- /* */
- /***************************************************************************/
- #include <ft2build.h>
- #include FT_CACHE_H
- #include FT_CACHE_MANAGER_H
- #include FT_CACHE_INTERNAL_LRU_H
- #include FT_INTERNAL_OBJECTS_H
- #include FT_INTERNAL_DEBUG_H
- #include FT_SIZES_H
- #include "ftcerror.h"
- #undef FT_COMPONENT
- #define FT_COMPONENT trace_cache
- #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** FACE LRU IMPLEMENTATION *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
- typedef struct FTC_FaceNodeRec_* FTC_FaceNode;
- typedef struct FTC_SizeNodeRec_* FTC_SizeNode;
- typedef struct FTC_FaceNodeRec_
- {
- FT_LruNodeRec lru;
- FT_Face face;
- } FTC_FaceNodeRec;
- typedef struct FTC_SizeNodeRec_
- {
- FT_LruNodeRec lru;
- FT_Size size;
- } FTC_SizeNodeRec;
- FT_CALLBACK_DEF( FT_Error )
- ftc_face_node_init( FTC_FaceNode node,
- FTC_FaceID face_id,
- FTC_Manager manager )
- {
- FT_Error error;
- error = manager->request_face( face_id,
- manager->library,
- manager->request_data,
- &node->face );
- if ( !error )
- {
- /* destroy initial size object; it will be re-created later */
- if ( node->face->size )
- FT_Done_Size( node->face->size );
- }
- return error;
- }
- /* helper function for ftc_face_node_done() */
- FT_CALLBACK_DEF( FT_Bool )
- ftc_size_node_select( FTC_SizeNode node,
- FT_Face face )
- {
- return FT_BOOL( node->size->face == face );
- }
- FT_CALLBACK_DEF( void )
- ftc_face_node_done( FTC_FaceNode node,
- FTC_Manager manager )
- {
- FT_Face face = node->face;
- /* we must begin by removing all sizes for the target face */
- /* from the manager's list */
- FT_LruList_Remove_Selection( manager->sizes_list,
- (FT_LruNode_SelectFunc)ftc_size_node_select,
- face );
- /* all right, we can discard the face now */
- FT_Done_Face( face );
- node->face = NULL;
- }
- FT_CALLBACK_TABLE_DEF
- const FT_LruList_ClassRec ftc_face_list_class =
- {
- sizeof ( FT_LruListRec ),
- (FT_LruList_InitFunc)0,
- (FT_LruList_DoneFunc)0,
- sizeof ( FTC_FaceNodeRec ),
- (FT_LruNode_InitFunc) ftc_face_node_init,
- (FT_LruNode_DoneFunc) ftc_face_node_done,
- (FT_LruNode_FlushFunc) 0, /* no flushing needed */
- (FT_LruNode_CompareFunc)0, /* direct comparison of FTC_FaceID handles */
- };
- /* documentation is in ftcache.h */
- FT_EXPORT_DEF( FT_Error )
- FTC_Manager_Lookup_Face( FTC_Manager manager,
- FTC_FaceID face_id,
- FT_Face *aface )
- {
- FT_Error error;
- FTC_FaceNode node;
- if ( aface == NULL )
- return FTC_Err_Bad_Argument;
- *aface = NULL;
- if ( !manager )
- return FTC_Err_Invalid_Cache_Handle;
- error = FT_LruList_Lookup( manager->faces_list,
- (FT_LruKey)face_id,
- (FT_LruNode*)&node );
- if ( !error )
- *aface = node->face;
- return error;
- }
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** SIZES LRU IMPLEMENTATION *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
- typedef struct FTC_SizeQueryRec_
- {
- FT_Face face;
- FT_UInt width;
- FT_UInt height;
- } FTC_SizeQueryRec, *FTC_SizeQuery;
- FT_CALLBACK_DEF( FT_Error )
- ftc_size_node_init( FTC_SizeNode node,
- FTC_SizeQuery query )
- {
- FT_Face face = query->face;
- FT_Size size;
- FT_Error error;
- node->size = NULL;
- error = FT_New_Size( face, &size );
- if ( !error )
- {
- FT_Activate_Size( size );
- error = FT_Set_Pixel_Sizes( query->face,
- query->width,
- query->height );
- if ( error )
- FT_Done_Size( size );
- else
- node->size = size;
- }
- return error;
- }
- FT_CALLBACK_DEF( void )
- ftc_size_node_done( FTC_SizeNode node )
- {
- if ( node->size )
- {
- FT_Done_Size( node->size );
- node->size = NULL;
- }
- }
- FT_CALLBACK_DEF( FT_Error )
- ftc_size_node_flush( FTC_SizeNode node,
- FTC_SizeQuery query )
- {
- FT_Size size = node->size;
- FT_Error error;
- if ( size->face == query->face )
- {
- FT_Activate_Size( size );
- error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
- if ( error )
- {
- FT_Done_Size( size );
- node->size = NULL;
- }
- }
- else
- {
- FT_Done_Size( size );
- node->size = NULL;
- error = ftc_size_node_init( node, query );
- }
- return error;
- }
- FT_CALLBACK_DEF( FT_Bool )
- ftc_size_node_compare( FTC_SizeNode node,
- FTC_SizeQuery query )
- {
- FT_Size size = node->size;
- return FT_BOOL( size->face == query->face &&
- (FT_UInt)size->metrics.x_ppem == query->width &&
- (FT_UInt)size->metrics.y_ppem == query->height );
- }
- FT_CALLBACK_TABLE_DEF
- const FT_LruList_ClassRec ftc_size_list_class =
- {
- sizeof ( FT_LruListRec ),
- (FT_LruList_InitFunc)0,
- (FT_LruList_DoneFunc)0,
- sizeof ( FTC_SizeNodeRec ),
- (FT_LruNode_InitFunc) ftc_size_node_init,
- (FT_LruNode_DoneFunc) ftc_size_node_done,
- (FT_LruNode_FlushFunc) ftc_size_node_flush,
- (FT_LruNode_CompareFunc)ftc_size_node_compare
- };
- /* documentation is in ftcache.h */
- FT_EXPORT_DEF( FT_Error )
- FTC_Manager_Lookup_Size( FTC_Manager manager,
- FTC_Font font,
- FT_Face *aface,
- FT_Size *asize )
- {
- FT_Error error;
- /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
- if ( aface )
- *aface = 0;
- if ( asize )
- *asize = 0;
- error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
- if ( !error )
- {
- FTC_SizeQueryRec query;
- FTC_SizeNode node;
- query.face = *aface;
- query.width = font->pix_width;
- query.height = font->pix_height;
- error = FT_LruList_Lookup( manager->sizes_list,
- (FT_LruKey)&query,
- (FT_LruNode*)&node );
- if ( !error )
- {
- /* select the size as the current one for this face */
- FT_Activate_Size( node->size );
- if ( asize )
- *asize = node->size;
- }
- }
- return error;
- }
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** SET TABLE MANAGEMENT *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
- static void
- ftc_family_table_init( FTC_FamilyTable table )
- {
- table->count = 0;
- table->size = 0;
- table->entries = NULL;
- table->free = FTC_FAMILY_ENTRY_NONE;
- }
- static void
- ftc_family_table_done( FTC_FamilyTable table,
- FT_Memory memory )
- {
- FT_FREE( table->entries );
- table->free = 0;
- table->count = 0;
- table->size = 0;
- }
- FT_EXPORT_DEF( FT_Error )
- ftc_family_table_alloc( FTC_FamilyTable table,
- FT_Memory memory,
- FTC_FamilyEntry *aentry )
- {
- FTC_FamilyEntry entry;
- FT_Error error = 0;
- /* re-allocate table size when needed */
- if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
- {
- FT_UInt old_size = table->size;
- FT_UInt new_size, idx;
- if ( old_size == 0 )
- new_size = 8;
- else
- {
- new_size = old_size * 2;
- /* check for (unlikely) overflow */
- if ( new_size < old_size )
- new_size = 65534;
- }
- if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
- return error;
- table->size = new_size;
- entry = table->entries + old_size;
- table->free = old_size;
- for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
- {
- entry->link = idx + 1;
- entry->index = idx;
- }
- entry->link = FTC_FAMILY_ENTRY_NONE;
- entry->index = idx;
- }
- if ( table->free != FTC_FAMILY_ENTRY_NONE )
- {
- entry = table->entries + table->free;
- table->free = entry->link;
- }
- else if ( table->count < table->size )
- {
- entry = table->entries + table->count++;
- }
- else
- {
- FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
- return FTC_Err_Invalid_Argument;
- }
- entry->link = FTC_FAMILY_ENTRY_NONE;
- table->count++;
- *aentry = entry;
- return error;
- }
- FT_EXPORT_DEF( void )
- ftc_family_table_free( FTC_FamilyTable table,
- FT_UInt idx )
- {
- /* simply add it to the linked list of free entries */
- if ( idx < table->count )
- {
- FTC_FamilyEntry entry = table->entries + idx;
- if ( entry->link != FTC_FAMILY_ENTRY_NONE )
- FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
- else
- {
- entry->link = table->free;
- table->free = entry->index;
- table->count--;
- }
- }
- }
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** CACHE MANAGER ROUTINES *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
- /* documentation is in ftcache.h */
- FT_EXPORT_DEF( FT_Error )
- FTC_Manager_New( FT_Library library,
- FT_UInt max_faces,
- FT_UInt max_sizes,
- FT_ULong max_bytes,
- FTC_Face_Requester requester,
- FT_Pointer req_data,
- FTC_Manager *amanager )
- {
- FT_Error error;
- FT_Memory memory;
- FTC_Manager manager = 0;
- if ( !library )
- return FTC_Err_Invalid_Library_Handle;
- memory = library->memory;
- if ( FT_NEW( manager ) )
- goto Exit;
- if ( max_faces == 0 )
- max_faces = FTC_MAX_FACES_DEFAULT;
- if ( max_sizes == 0 )
- max_sizes = FTC_MAX_SIZES_DEFAULT;
- if ( max_bytes == 0 )
- max_bytes = FTC_MAX_BYTES_DEFAULT;
- error = FT_LruList_New( &ftc_face_list_class,
- max_faces,
- manager,
- memory,
- &manager->faces_list );
- if ( error )
- goto Exit;
- error = FT_LruList_New( &ftc_size_list_class,
- max_sizes,
- manager,
- memory,
- &manager->sizes_list );
- if ( error )
- goto Exit;
- manager->library = library;
- manager->max_weight = max_bytes;
- manager->cur_weight = 0;
- manager->request_face = requester;
- manager->request_data = req_data;
- ftc_family_table_init( &manager->families );
- *amanager = manager;
- Exit:
- if ( error && manager )
- {
- FT_LruList_Destroy( manager->faces_list );
- FT_LruList_Destroy( manager->sizes_list );
- FT_FREE( manager );
- }
- return error;
- }
- /* documentation is in ftcache.h */
- FT_EXPORT_DEF( void )
- FTC_Manager_Done( FTC_Manager manager )
- {
- FT_Memory memory;
- FT_UInt idx;
- if ( !manager || !manager->library )
- return;
- memory = manager->library->memory;
- /* now discard all caches */
- for (idx = 0; idx < FTC_MAX_CACHES; idx++ )
- {
- FTC_Cache cache = manager->caches[idx];
- if ( cache )
- {
- cache->clazz->cache_done( cache );
- FT_FREE( cache );
- manager->caches[idx] = 0;
- }
- }
- /* discard families table */
- ftc_family_table_done( &manager->families, memory );
- /* discard faces and sizes */
- FT_LruList_Destroy( manager->faces_list );
- manager->faces_list = 0;
- FT_LruList_Destroy( manager->sizes_list );
- manager->sizes_list = 0;
- FT_FREE( manager );
- }
- /* documentation is in ftcache.h */
- FT_EXPORT_DEF( void )
- FTC_Manager_Reset( FTC_Manager manager )
- {
- if ( manager )
- {
- FT_LruList_Reset( manager->sizes_list );
- FT_LruList_Reset( manager->faces_list );
- }
- /* XXX: FIXME: flush the caches? */
- }
- #ifdef FT_DEBUG_ERROR
- FT_EXPORT_DEF( void )
- FTC_Manager_Check( FTC_Manager manager )
- {
- FTC_Node node, first;
-
- first = manager->nodes_list;
- /* check node weights */
- if ( first )
- {
- FT_ULong weight = 0;
-
- node = first;
- do
- {
- FTC_FamilyEntry entry = manager->families.entries + node->fam_index;
- FTC_Cache cache;
- if ( (FT_UInt)node->fam_index >= manager->families.count ||
- entry->link != FTC_FAMILY_ENTRY_NONE )
- FT_ERROR(( "FTC_Manager_Check: invalid node (family index = %ld\n",
- node->fam_index ));
- else
- {
- cache = entry->cache;
- weight += cache->clazz->node_weight( node, cache );
- }
- node = node->mru_next;
- } while ( node != first );
- if ( weight != manager->cur_weight )
- FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
- manager->cur_weight, weight ));
- }
- /* check circular list */
- if ( first )
- {
- FT_UFast count = 0;
- node = first;
- do
- {
- count++;
- node = node->mru_next;
- } while ( node != first );
- if ( count != manager->num_nodes )
- FT_ERROR((
- "FTC_Manager_Check: invalid cache node count %d instead of %d\n",
- manager->num_nodes, count ));
- }
- }
- #endif /* FT_DEBUG_ERROR */
- /* `Compress' the manager's data, i.e., get rid of old cache nodes */
- /* that are not referenced anymore in order to limit the total */
- /* memory used by the cache. */
- /* documentation is in ftcmanag.h */
- FT_EXPORT_DEF( void )
- FTC_Manager_Compress( FTC_Manager manager )
- {
- FTC_Node node, first;
- if ( !manager )
- return;
- first = manager->nodes_list;
- #ifdef FT_DEBUG_ERROR
- FTC_Manager_Check( manager );
- FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
- manager->cur_weight, manager->max_weight,
- manager->num_nodes ));
- #endif
- if ( manager->cur_weight < manager->max_weight || first == NULL )
- return;
- /* go to last node - it's a circular list */
- node = first->mru_prev;
- do
- {
- FTC_Node prev = node->mru_prev;
- prev = ( node == first ) ? NULL : node->mru_prev;
- if ( node->ref_count <= 0 )
- ftc_node_destroy( node, manager );
- node = prev;
- } while ( node && manager->cur_weight > manager->max_weight );
- }
- /* documentation is in ftcmanag.h */
- FT_EXPORT_DEF( FT_Error )
- FTC_Manager_Register_Cache( FTC_Manager manager,
- FTC_Cache_Class clazz,
- FTC_Cache *acache )
- {
- FT_Error error = FTC_Err_Invalid_Argument;
- FTC_Cache cache = NULL;
- if ( manager && clazz && acache )
- {
- FT_Memory memory = manager->library->memory;
- FT_UInt idx = 0;
- /* check for an empty cache slot in the manager's table */
- for ( idx = 0; idx < FTC_MAX_CACHES; idx++ )
- {
- if ( manager->caches[idx] == 0 )
- break;
- }
- /* return an error if there are too many registered caches */
- if ( idx >= FTC_MAX_CACHES )
- {
- error = FTC_Err_Too_Many_Caches;
- FT_ERROR(( "FTC_Manager_Register_Cache:" ));
- FT_ERROR(( " too many registered caches\n" ));
- goto Exit;
- }
- if ( !FT_ALLOC( cache, clazz->cache_size ) )
- {
- cache->manager = manager;
- cache->memory = memory;
- cache->clazz = clazz;
- /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
- /* IF IT IS NOT SET CORRECTLY */
- cache->cache_index = idx;
- if ( clazz->cache_init )
- {
- error = clazz->cache_init( cache );
- if ( error )
- {
- if ( clazz->cache_done )
- clazz->cache_done( cache );
- FT_FREE( cache );
- goto Exit;
- }
- }
- manager->caches[idx] = cache;
- }
- }
- Exit:
- *acache = cache;
- return error;
- }
- /* documentation is in ftcmanag.h */
- FT_EXPORT_DEF( void )
- FTC_Node_Unref( FTC_Node node,
- FTC_Manager manager )
- {
- if ( node && (FT_UInt)node->fam_index < manager->families.count &&
- manager->families.entries[node->fam_index].cache )
- {
- node->ref_count--;
- }
- }
- /* END */
|