diff options
Diffstat (limited to 'src/cache')
-rw-r--r-- | src/cache/ftcbasic.c | 766 | ||||
-rw-r--r-- | src/cache/ftccache.c | 1143 | ||||
-rw-r--r-- | src/cache/ftccmap.c | 537 | ||||
-rw-r--r-- | src/cache/ftcglyph.c | 305 | ||||
-rw-r--r-- | src/cache/ftcmanag.c | 1268 |
5 files changed, 2039 insertions, 1980 deletions
diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c index b1f825ed7..3f8954830 100644 --- a/src/cache/ftcbasic.c +++ b/src/cache/ftcbasic.c @@ -1,373 +1,393 @@ -#include <ft2build.h> -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_GLYPH_H -#include FT_CACHE_INTERNAL_IMAGE_H -#include FT_CACHE_INTERNAL_SBITS_H -#include FT_INTERNAL_MEMORY_H - -#include "ftcerror.h" - - - /* - * Basic Families - * - * - */ - typedef struct FTC_BasicAttrRec_ - { - FTC_ScalerRec scaler; - FT_UInt load_flags; - - } FTC_BasicAttrRec, *FTC_BasicAttrs; - -#define FTC_BASIC_ATTR_COMPARE(a,b) \ - ( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \ - (a)->load_flags == (b)->load_flags ) - -#define FTC_BASIC_ATTR_HASH(a) \ - ( FTC_SCALER_HASH(&(a)->scaler) + 31*(a)->load_flags ) - - - typedef struct FTC_BasicQueryRec_ - { - FTC_GQueryRec gquery; - FTC_BasicAttrRec attrs; - - } FTC_BasicQueryRec, *FTC_BasicQuery; - - - - typedef struct FTC_BasicFamilyRec_ - { - FTC_FamilyRec family; - FTC_BasicAttrRec attrs; - - } FTC_BasicFamilyRec, *FTC_BasicFamily; - - - static FT_Bool - ftc_basic_family_compare( FTC_BasicFamily family, - FTC_BasicQuery query ) - { - return FT_BOOL( FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ) ); - } - - static FT_Error - ftc_basic_family_init( FTC_BasicFamily family, - FTC_BasicQuery query, - FTC_Cache cache ) - { - FTC_Family_Init( FTC_FAMILY( family ), cache ); - family->attrs = query->attrs; - return 0; - } - - - static FT_UInt - ftc_basic_family_get_count( FTC_BasicFamily family, - FTC_Manager manager ) - { - FT_Error error; - FT_Face face; - FT_UInt result = 0; - - error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id, - &face ); - if ( !error ) - result = face->num_glyphs; - - return result; - } - - - static FT_Error - ftc_basic_family_load_bitmap( FTC_BasicFamily family, - FT_UInt gindex, - FTC_Manager manager, - FT_Face *aface ) - { - FT_Error error; - FT_Size size; - - error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size ); - if ( !error ) - { - FT_Face face = size->face; - - error = FT_Load_Glyph( face, gindex, family->attrs.load_flags | - FT_LOAD_RENDER ); - if ( !error ) - *aface = face; - } - return error; - } - - - static FT_Error - ftc_basic_family_load_glyph( FTC_BasicFamily family, - FT_UInt gindex, - FTC_Cache cache, - FT_Glyph *aglyph ) - { - FT_Error error; - FTC_Scaler scaler = &family->attrs.scaler; - FT_Face face; - FT_Size size; - - /* we will now load the glyph image */ - error = FTC_Manager_LookupSize( cache->manager, - scaler, - &size ); - if ( !error ) - { - face = size->face; - - error = FT_Load_Glyph( face, gindex, family->attrs.load_flags ); - if ( !error ) - { - if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP || - face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ) - { - /* ok, copy it */ - FT_Glyph glyph; - - - error = FT_Get_Glyph( face->glyph, &glyph ); - if ( !error ) - { - *aglyph = glyph; - goto Exit; - } - } - else - error = FTC_Err_Invalid_Argument; - } - } - Exit: - return error; - } - - - static FT_Bool - ftc_basic_gnode_compare_faceid( FTC_GNode gnode, - FTC_FaceID face_id, - FTC_Cache cache ) - { - FTC_BasicFamily family = (FTC_BasicFamily) gnode->family; - FT_Bool result; - - result = FT_BOOL( family->attrs.scaler.face_id == face_id ); - if ( result ) - { - /* we must call this function to avoid this node from appearing - * in later lookups with the same face_id !! - */ - FTC_GNode_UnselectFamily( gnode, cache ); - } - return result; - } - - - - /* - * - * basic image cache - * - */ - - static const FTC_IFamilyClassRec ftc_basic_image_family_class = - { - { - sizeof( FTC_BasicFamilyRec ), - (FTC_MruNode_CompareFunc) ftc_basic_family_compare, - (FTC_MruNode_InitFunc) ftc_basic_family_init, - (FTC_MruNode_ResetFunc) NULL, - (FTC_MruNode_DoneFunc) NULL - }, - (FTC_IFamily_LoadGlyphFunc) ftc_basic_family_load_glyph - }; - - - - static const FTC_GCacheClassRec ftc_basic_image_cache_class = - { - { - (FTC_Node_NewFunc) FTC_INode_New, - (FTC_Node_WeightFunc) FTC_INode_Weight, - (FTC_Node_CompareFunc) FTC_GNode_Compare, - (FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid, - (FTC_Node_FreeFunc) FTC_INode_Free, - - sizeof( FTC_GCacheRec ), - (FTC_Cache_InitFunc) FTC_GCache_Init, - (FTC_Cache_DoneFunc) FTC_GCache_Done - }, - (FTC_MruListClass) & ftc_basic_image_family_class - }; - - - FT_EXPORT_DEF( FT_Error ) - FTC_ImageCache_New( FTC_Manager manager, - FTC_ImageCache *acache ) - { - return FTC_GCache_New( manager, & ftc_basic_image_cache_class, - (FTC_GCache*) acache ); - } - - - /* documentation is in ftcimage.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_ImageCache_Lookup( FTC_ImageCache cache, - FTC_ImageType type, - FT_UInt gindex, - FT_Glyph *aglyph, - FTC_Node *anode ) - { - FTC_BasicQueryRec query; - FTC_INode node; - FT_Error error; - FT_UInt32 hash; - - - /* some argument checks are delayed to FTC_Cache_Lookup */ - if ( !aglyph ) - { - error = FTC_Err_Invalid_Argument; - goto Exit; - } - - *aglyph = NULL; - if ( anode ) - *anode = NULL; - - query.attrs.scaler.face_id = type->face_id; - query.attrs.scaler.width = type->width; - query.attrs.scaler.height = type->height; - query.attrs.scaler.pixel = 1; - query.attrs.load_flags = type->flags; - - hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; - - error = FTC_GCache_Lookup( FTC_GCACHE( cache ), - hash, gindex, - FTC_GQUERY( &query ), - (FTC_Node*) &node ); - if ( !error ) - { - *aglyph = FTC_INODE(node)->glyph; - - if ( anode ) - { - *anode = FTC_NODE(node); - FTC_NODE(node)->ref_count++; - } - } - - Exit: - return error; - } - - - - /* - * - * basic small bitmap cache - * - */ - - - static const FTC_SFamilyClassRec ftc_basic_sbit_family_class = - { - { - sizeof( FTC_BasicFamilyRec ), - (FTC_MruNode_CompareFunc) ftc_basic_family_compare, - (FTC_MruNode_InitFunc) ftc_basic_family_init, - (FTC_MruNode_ResetFunc) NULL, - (FTC_MruNode_DoneFunc) NULL - }, - (FTC_SFamily_GetCountFunc) ftc_basic_family_get_count, - (FTC_SFamily_LoadGlyphFunc) ftc_basic_family_load_bitmap - }; - - - static const FTC_GCacheClassRec ftc_basic_sbit_cache_class = - { - { - (FTC_Node_NewFunc) FTC_SNode_New, - (FTC_Node_WeightFunc) FTC_SNode_Weight, - (FTC_Node_CompareFunc) FTC_SNode_Compare, - (FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid, - (FTC_Node_FreeFunc) FTC_SNode_Free, - - sizeof( FTC_GCacheRec ), - (FTC_Cache_InitFunc) FTC_GCache_Init, - (FTC_Cache_DoneFunc) FTC_GCache_Done - }, - (FTC_MruListClass) & ftc_basic_sbit_family_class - }; - - - - - FT_EXPORT_DEF( FT_Error ) - FTC_SBitCache_New( FTC_Manager manager, - FTC_SBitCache *acache ) - { - return FTC_GCache_New( manager, & ftc_basic_sbit_cache_class, - (FTC_GCache*) acache ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_SBitCache_Lookup( FTC_SBitCache cache, - FTC_ImageType type, - FT_UInt gindex, - FTC_SBit *ansbit, - FTC_Node *anode ) - { - FT_Error error; - FTC_BasicQueryRec query; - FTC_SNode node; - FT_UInt32 hash; - - if ( anode ) - *anode = NULL; - - /* other argument checks delayed to FTC_Cache_Lookup */ - if ( !ansbit ) - return FTC_Err_Invalid_Argument; - - *ansbit = NULL; - - query.attrs.scaler.face_id = type->face_id; - query.attrs.scaler.width = type->width; - query.attrs.scaler.height = type->height; - query.attrs.scaler.pixel = 1; - query.attrs.load_flags = type->flags; - - /* beware, the hash must be the same for all glyph ranges !! - */ - hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + - (gindex/FTC_SBIT_ITEMS_PER_NODE); - - error = FTC_GCache_Lookup( FTC_GCACHE( cache ), - hash, - gindex, - FTC_GQUERY( &query ), - (FTC_Node*) &node ); - if ( error ) - goto Exit; - - *ansbit = node->sbits + ( gindex - FTC_GNODE(node)->gindex ); - - if ( anode ) - { - *anode = FTC_NODE( node ); - FTC_NODE( node )->ref_count++; - } - - Exit: - return error; - } - +#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_CACHE_INTERNAL_IMAGE_H
+#include FT_CACHE_INTERNAL_SBITS_H
+#include FT_INTERNAL_MEMORY_H
+
+#include "ftcerror.h"
+
+
+ /*
+ * Basic Families
+ *
+ *
+ */
+ typedef struct FTC_BasicAttrRec_
+ {
+ FTC_ScalerRec scaler;
+ FT_UInt load_flags;
+
+ } FTC_BasicAttrRec, *FTC_BasicAttrs;
+
+#define FTC_BASIC_ATTR_COMPARE(a,b) \
+ ( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
+ (a)->load_flags == (b)->load_flags )
+
+#define FTC_BASIC_ATTR_HASH(a) \
+ ( FTC_SCALER_HASH(&(a)->scaler) + 31*(a)->load_flags )
+
+
+ typedef struct FTC_BasicQueryRec_
+ {
+ FTC_GQueryRec gquery;
+ FTC_BasicAttrRec attrs;
+
+ } FTC_BasicQueryRec, *FTC_BasicQuery;
+
+
+
+ typedef struct FTC_BasicFamilyRec_
+ {
+ FTC_FamilyRec family;
+ FTC_BasicAttrRec attrs;
+
+ } FTC_BasicFamilyRec, *FTC_BasicFamily;
+
+
+ static FT_Bool
+ ftc_basic_family_compare( FTC_BasicFamily family,
+ FTC_BasicQuery query )
+ {
+ return FT_BOOL( FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ) );
+ }
+
+ static FT_Error
+ ftc_basic_family_init( FTC_BasicFamily family,
+ FTC_BasicQuery query,
+ FTC_Cache cache )
+ {
+ FTC_Family_Init( FTC_FAMILY( family ), cache );
+ family->attrs = query->attrs;
+ return 0;
+ }
+
+
+ static FT_UInt
+ ftc_basic_family_get_count( FTC_BasicFamily family,
+ FTC_Manager manager )
+ {
+ FT_Error error;
+ FT_Face face;
+ FT_UInt result = 0;
+
+ error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
+ &face );
+ if ( !error )
+ result = face->num_glyphs;
+
+ return result;
+ }
+
+
+ static FT_Error
+ ftc_basic_family_load_bitmap( FTC_BasicFamily family,
+ FT_UInt gindex,
+ FTC_Manager manager,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FT_Size size;
+
+ error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
+ if ( !error )
+ {
+ FT_Face face = size->face;
+
+ error = FT_Load_Glyph( face, gindex, family->attrs.load_flags |
+ FT_LOAD_RENDER );
+ if ( !error )
+ *aface = face;
+ }
+ return error;
+ }
+
+
+ static FT_Error
+ ftc_basic_family_load_glyph( FTC_BasicFamily family,
+ FT_UInt gindex,
+ FTC_Cache cache,
+ FT_Glyph *aglyph )
+ {
+ FT_Error error;
+ FTC_Scaler scaler = &family->attrs.scaler;
+ FT_Face face;
+ FT_Size size;
+
+ /* we will now load the glyph image */
+ error = FTC_Manager_LookupSize( cache->manager,
+ scaler,
+ &size );
+ if ( !error )
+ {
+ face = size->face;
+
+ error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
+ if ( !error )
+ {
+ if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP ||
+ face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* ok, copy it */
+ FT_Glyph glyph;
+
+
+ error = FT_Get_Glyph( face->glyph, &glyph );
+ if ( !error )
+ {
+ *aglyph = glyph;
+ goto Exit;
+ }
+ }
+ else
+ error = FTC_Err_Invalid_Argument;
+ }
+ }
+ Exit:
+ return error;
+ }
+
+
+ static FT_Bool
+ ftc_basic_gnode_compare_faceid( FTC_GNode gnode,
+ FTC_FaceID face_id,
+ FTC_Cache cache )
+ {
+ FTC_BasicFamily family = (FTC_BasicFamily) gnode->family;
+ FT_Bool result;
+
+ result = FT_BOOL( family->attrs.scaler.face_id == face_id );
+ if ( result )
+ {
+ /* we must call this function to avoid this node from appearing
+ * in later lookups with the same face_id !!
+ */
+ FTC_GNode_UnselectFamily( gnode, cache );
+ }
+ return result;
+ }
+
+
+
+ /*
+ *
+ * basic image cache
+ *
+ */
+
+ static const FTC_IFamilyClassRec ftc_basic_image_family_class =
+ {
+ {
+ sizeof( FTC_BasicFamilyRec ),
+ (FTC_MruNode_CompareFunc) ftc_basic_family_compare,
+ (FTC_MruNode_InitFunc) ftc_basic_family_init,
+ (FTC_MruNode_ResetFunc) NULL,
+ (FTC_MruNode_DoneFunc) NULL
+ },
+ (FTC_IFamily_LoadGlyphFunc) ftc_basic_family_load_glyph
+ };
+
+
+
+ static const FTC_GCacheClassRec ftc_basic_image_cache_class =
+ {
+ {
+ (FTC_Node_NewFunc) FTC_INode_New,
+ (FTC_Node_WeightFunc) FTC_INode_Weight,
+ (FTC_Node_CompareFunc) FTC_GNode_Compare,
+ (FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid,
+ (FTC_Node_FreeFunc) FTC_INode_Free,
+
+ sizeof( FTC_GCacheRec ),
+ (FTC_Cache_InitFunc) FTC_GCache_Init,
+ (FTC_Cache_DoneFunc) FTC_GCache_Done
+ },
+ (FTC_MruListClass) & ftc_basic_image_family_class
+ };
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ImageCache_New( FTC_Manager manager,
+ FTC_ImageCache *acache )
+ {
+ return FTC_GCache_New( manager, & ftc_basic_image_cache_class,
+ (FTC_GCache*) acache );
+ }
+
+
+ /* documentation is in ftcimage.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ImageCache_Lookup( FTC_ImageCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FT_Glyph *aglyph,
+ FTC_Node *anode )
+ {
+ FTC_BasicQueryRec query;
+ FTC_INode node;
+ FT_Error error;
+ FT_UInt32 hash;
+
+
+ /* some argument checks are delayed to FTC_Cache_Lookup */
+ if ( !aglyph )
+ {
+ error = FTC_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ *aglyph = NULL;
+ if ( anode )
+ *anode = NULL;
+
+ query.attrs.scaler.face_id = type->face_id;
+ query.attrs.scaler.width = type->width;
+ query.attrs.scaler.height = type->height;
+ query.attrs.scaler.pixel = 1;
+ query.attrs.load_flags = type->flags;
+
+ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
+
+#if 1 /* inlining is about 50% faster !! */
+ FTC_GCACHE_LOOKUP_CMP( cache,
+ ftc_basic_family_compare,
+ FTC_GNode_Compare,
+ hash, gindex,
+ &query,
+ node,
+ error );
+#else
+ error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
+ hash, gindex,
+ FTC_GQUERY( &query ),
+ (FTC_Node*) &node );
+#endif
+ if ( !error )
+ {
+ *aglyph = FTC_INODE(node)->glyph;
+
+ if ( anode )
+ {
+ *anode = FTC_NODE(node);
+ FTC_NODE(node)->ref_count++;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+ /*
+ *
+ * basic small bitmap cache
+ *
+ */
+
+
+ static const FTC_SFamilyClassRec ftc_basic_sbit_family_class =
+ {
+ {
+ sizeof( FTC_BasicFamilyRec ),
+ (FTC_MruNode_CompareFunc) ftc_basic_family_compare,
+ (FTC_MruNode_InitFunc) ftc_basic_family_init,
+ (FTC_MruNode_ResetFunc) NULL,
+ (FTC_MruNode_DoneFunc) NULL
+ },
+ (FTC_SFamily_GetCountFunc) ftc_basic_family_get_count,
+ (FTC_SFamily_LoadGlyphFunc) ftc_basic_family_load_bitmap
+ };
+
+
+ static const FTC_GCacheClassRec ftc_basic_sbit_cache_class =
+ {
+ {
+ (FTC_Node_NewFunc) FTC_SNode_New,
+ (FTC_Node_WeightFunc) FTC_SNode_Weight,
+ (FTC_Node_CompareFunc) FTC_SNode_Compare,
+ (FTC_Node_CompareFunc) ftc_basic_gnode_compare_faceid,
+ (FTC_Node_FreeFunc) FTC_SNode_Free,
+
+ sizeof( FTC_GCacheRec ),
+ (FTC_Cache_InitFunc) FTC_GCache_Init,
+ (FTC_Cache_DoneFunc) FTC_GCache_Done
+ },
+ (FTC_MruListClass) & ftc_basic_sbit_family_class
+ };
+
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBitCache_New( FTC_Manager manager,
+ FTC_SBitCache *acache )
+ {
+ return FTC_GCache_New( manager, & ftc_basic_sbit_cache_class,
+ (FTC_GCache*) acache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBitCache_Lookup( FTC_SBitCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FTC_SBit *ansbit,
+ FTC_Node *anode )
+ {
+ FT_Error error;
+ FTC_BasicQueryRec query;
+ FTC_SNode node;
+ FT_UInt32 hash;
+
+ if ( anode )
+ *anode = NULL;
+
+ /* other argument checks delayed to FTC_Cache_Lookup */
+ if ( !ansbit )
+ return FTC_Err_Invalid_Argument;
+
+ *ansbit = NULL;
+
+ query.attrs.scaler.face_id = type->face_id;
+ query.attrs.scaler.width = type->width;
+ query.attrs.scaler.height = type->height;
+ query.attrs.scaler.pixel = 1;
+ query.attrs.load_flags = type->flags;
+
+ /* beware, the hash must be the same for all glyph ranges !!
+ */
+ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
+ (gindex/FTC_SBIT_ITEMS_PER_NODE);
+
+#if 1 /* inlining is about 50% faster !! */
+ FTC_GCACHE_LOOKUP_CMP( cache,
+ ftc_basic_family_compare,
+ FTC_SNode_Compare,
+ hash, gindex,
+ &query,
+ node,
+ error );
+#else
+ error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
+ hash,
+ gindex,
+ FTC_GQUERY( &query ),
+ (FTC_Node*) &node );
+#endif
+ if ( error )
+ goto Exit;
+
+ *ansbit = node->sbits + ( gindex - FTC_GNODE(node)->gindex );
+
+ if ( anode )
+ {
+ *anode = FTC_NODE( node );
+ FTC_NODE( node )->ref_count++;
+ }
+
+ Exit:
+ return error;
+ }
+
diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c index e3b5bfcae..4db40a232 100644 --- a/src/cache/ftccache.c +++ b/src/cache/ftccache.c @@ -1,565 +1,578 @@ -/***************************************************************************/ -/* */ -/* ftccache.c */ -/* */ -/* The FreeType internal cache interface (body). */ -/* */ -/* Copyright 2000-2001, 2002, 2003 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_INTERNAL_MANAGER_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H - -#include "ftcerror.h" - - -#define FTC_HASH_MAX_LOAD 2 -#define FTC_HASH_MIN_LOAD 1 -#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD ) - -/* this one _must_ be a power of 2! */ -#define FTC_HASH_INITIAL_SIZE 8 - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE NODE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* add a new node to the head of the manager's circular MRU list */ - static void - ftc_node_mru_link( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Prepend( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - manager->num_nodes++; - } - - - /* remove a node from the manager's MRU list */ - static void - ftc_node_mru_unlink( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Remove( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - manager->num_nodes--; - } - - - /* move a node to the head of the manager's MRU list */ - static void - ftc_node_mru_up( FTC_Node node, - FTC_Manager manager ) - { - FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node ); - } - - - /* note that this function cannot fail. If we cannot re-size the - * buckets array appropriately, we simply degrade the hash table's - * performance !! - */ - static void - ftc_cache_resize( FTC_Cache cache ) - { - for (;;) - { - FTC_Node node, *pnode; - FT_UInt p = cache->p; - FT_UInt mask = cache->mask; - FT_UInt count = mask + p + 1; /* number of buckets */ - - /* do we need to shrink the buckets array ? - */ - if ( cache->slack < 0 ) - { - FTC_Node new_list = NULL; - - /* try to expand the buckets array _before_ splitting - * the bucket lists - */ - if ( p >= mask ) - { - FT_Memory memory = cache->memory; - - /* if we can't expand the array, leave immediately */ - if ( FT_MEM_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) ) - break; - } - - /* split a single bucket */ - pnode = cache->buckets + p; - - for (;;) - { - node = *pnode; - if ( node == NULL ) - break; - - if ( node->hash & ( mask + 1 ) ) - { - *pnode = node->link; - node->link = new_list; - new_list = node; - } - else - pnode = &node->link; - } - - cache->buckets[p + mask + 1] = new_list; - - cache->slack += FTC_HASH_MAX_LOAD; - - if ( p >= mask ) - { - cache->mask = 2 * mask + 1; - cache->p = 0; - } - else - cache->p = p + 1; - } - /* do we need to expand the buckets array ? - */ - else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD ) - { - FT_UInt old_index = p + mask; - FTC_Node* pold; - - if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) - break; - - if ( p == 0 ) - { - FT_Memory memory = cache->memory; - - /* if we can't shrink the array, leave immediately */ - if ( FT_MEM_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) ) - break; - - cache->mask >>= 1; - p = cache->mask; - } - else - p--; - - pnode = cache->buckets + p; - while ( *pnode ) - pnode = &(*pnode)->link; - - pold = cache->buckets + old_index; - *pnode = *pold; - *pold = NULL; - - cache->slack -= FTC_HASH_MAX_LOAD; - cache->p = p; - } - else /* the hash table is balanced */ - break; - } - } - - - - /* remove a node from its cache's hash table */ - static void - ftc_node_hash_unlink( FTC_Node node0, - FTC_Cache cache ) - { - FTC_Node *pnode; - FT_UInt idx; - - - idx = (FT_UInt)( node0->hash & cache->mask ); - if ( idx < cache->p ) - idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) ); - - pnode = cache->buckets + idx; - - for (;;) - { - FTC_Node node = *pnode; - - if ( node == NULL ) - { - FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" )); - return; - } - - if ( node == node0 ) - break; - - pnode = &(*pnode)->link; - } - - *pnode = node0->link; - node0->link = NULL; - - cache->slack++; - ftc_cache_resize( cache ); - } - - - - /* add a node to the "top" of its cache's hash table */ - static void - ftc_node_hash_link( FTC_Node node, - FTC_Cache cache ) - { - FTC_Node *pnode; - FT_UInt idx; - - - idx = (FT_UInt)( node->hash & cache->mask ); - if ( idx < cache->p ) - idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) ); - - pnode = cache->buckets + idx; - - node->link = *pnode; - *pnode = node; - - cache->slack--; - ftc_cache_resize( cache ); - } - - - - - /* remove a node from the cache manager */ - FT_EXPORT_DEF( void ) - ftc_node_destroy( FTC_Node node, - FTC_Manager manager ) - { - FTC_Cache cache; - - -#ifdef FT_DEBUG_ERROR - /* find node's cache */ - if ( node->cache_index >= manager->num_caches ) - { - FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); - return; - } -#endif - - cache = manager->caches[ node->cache_index ]; - -#ifdef FT_DEBUG_ERROR - if ( cache == NULL ) - { - FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); - return; - } -#endif - - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - - /* remove node from mru list */ - ftc_node_mru_unlink( node, manager ); - - /* remove node from cache's hash table */ - ftc_node_hash_unlink( node, cache ); - - /* now finalize it */ - cache->clazz.node_free( node, cache ); - -#if 0 - /* check, just in case of general corruption :-) */ - if ( manager->num_nodes == 0 ) - FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n", - manager->num_nodes )); -#endif - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** ABSTRACT CACHE CLASS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_EXPORT( FT_Error ) - FTC_Cache_Init( FTC_Cache cache ) - { - FT_Memory memory = cache->memory; - - cache->p = 0; - cache->mask = FTC_HASH_INITIAL_SIZE - 1; - cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; - - return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) ); - } - - - - FT_EXPORT_DEF( void ) - FTC_Cache_Clear( FTC_Cache cache ) - { - if ( cache ) - { - FTC_Manager manager = cache->manager; - FT_UFast i; - FT_UInt count; - - count = cache->p + cache->mask + 1; - - for ( i = 0; i < count; i++ ) - { - FTC_Node *pnode = cache->buckets + i, next, node = *pnode; - - - while ( node ) - { - next = node->link; - node->link = NULL; - - /* remove node from mru list */ - ftc_node_mru_unlink( node, manager ); - - /* now finalize it */ - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - - cache->clazz.node_free( node, cache ); - node = next; - } - cache->buckets[i] = NULL; - } - ftc_cache_resize( cache ); - } - } - - - FT_EXPORT( void ) - FTC_Cache_Done( FTC_Cache cache ) - { - if ( cache->memory ) - { - FT_Memory memory = cache->memory; - - FTC_Cache_Clear( cache ); - - FT_FREE( cache->buckets ); - cache->mask = 0; - cache->p = 0; - cache->slack = 0; - - cache->memory = NULL; - } - } - - - - static void - ftc_cache_add( FTC_Cache cache, - FT_UInt32 hash, - FTC_Node node ) - { - node->hash = hash; - node->cache_index = (FT_UInt16) cache->index; - node->ref_count = 0; - - ftc_node_hash_link( node, cache ); - ftc_node_mru_link( node, cache->manager ); - - { - FTC_Manager manager = cache->manager; - - manager->cur_weight += cache->clazz.node_weight( node, cache ); - - if ( manager->cur_weight >= manager->max_weight ) - { - node->ref_count++; - FTC_Manager_Compress( manager ); - node->ref_count--; - } - } - } - - - FT_EXPORT( FT_Error ) - FTC_Cache_Lookup( FTC_Cache cache, - FT_UInt32 hash, - FT_Pointer query, - FTC_Node *anode ) - { - FT_UFast idx; - FTC_Node* bucket; - FTC_Node* pnode; - FTC_Node node; - FT_Error error = 0; - - FTC_Node_CompareFunc compare = cache->clazz.node_compare; - - - if ( cache == NULL || anode == NULL ) - return FT_Err_Invalid_Argument; - - idx = hash & cache->mask; - if ( idx < cache->p ) - idx = hash & ( cache->mask * 2 + 1 ); - - bucket = cache->buckets + idx; - pnode = bucket; - for (;;) - { - node = *pnode; - if ( node == NULL ) - goto NewNode; - - if ( node->hash == hash && compare( node, query, cache ) ) - break; - - pnode = &node->link; - } - - if ( node != *bucket ) - { - *pnode = node->link; - node->link = *bucket; - *bucket = node; - } - - /* move to head of MRU list */ - { - FTC_Manager manager = cache->manager; - - if ( node != manager->nodes_list ) - ftc_node_mru_up( node, manager ); - } - goto Exit; - - NewNode: - - /* - * try to allocate a new cache node. Note that in case of - * out-of-memory error (OOM), we'll flush the cache a bit, - * then try again. - * - * on each try, the "tries" variable gives the number - * of old nodes we want to flush from the manager's global list - * before the next allocation attempt. it barely doubles on - * each iteration - * - */ - error = cache->clazz.node_new( &node, query, cache ); - if ( error ) - goto FlushCache; - - AddNode: - /* don't assume that the cache has the same number of buckets, since - * our allocation request might have triggered global cache flushing - */ - ftc_cache_add( cache, hash, node ); - - Exit: - *anode = node; - return error; - - FlushCache: - node = NULL; - if ( error != FT_Err_Out_Of_Memory ) - goto Exit; - - { - FTC_Manager manager = cache->manager; - FT_UInt count, tries = 1; - - for (;;) - { - error = cache->clazz.node_new( &node, query, cache ); - if ( !error ) - break; - - node = NULL; - if ( error != FT_Err_Out_Of_Memory ) - goto Exit; - - count = FTC_Manager_FlushN( manager, tries ); - if ( count == 0 ) - goto Exit; - - if ( count == tries ) - { - count = tries*2; - if ( count < tries || count > manager->num_nodes ) - count = manager->num_nodes; - } - tries = count; - } - } - goto AddNode; - } - - - - - FT_EXPORT( void ) - FTC_Cache_RemoveFaceID( FTC_Cache cache, - FTC_FaceID face_id ) - { - FT_UFast i, count; - FTC_Manager manager = cache->manager; - FTC_Node free = NULL; - - count = cache->p + cache->mask; - for ( i = 0; i < count; i++ ) - { - FTC_Node* bucket = cache->buckets + i; - FTC_Node* pnode = bucket; - - for ( ;; ) - { - FTC_Node node = *pnode; - - if ( node == NULL ) - break; - - if ( cache->clazz.node_remove_faceid( node, face_id, cache ) ) - { - *pnode = node->link; - node->link = free; - free = node; - } - else - pnode = &node->link; - } - } - - /* remove all nodes in the free list - */ - while ( free ) - { - FTC_Node node; - - node = free; - free = node->link; - - manager->cur_weight -= cache->clazz.node_weight( node, cache ); - ftc_node_mru_unlink( node, manager ); - - cache->clazz.node_free( node, cache ); - - cache->slack ++; - } - - ftc_cache_resize( cache ); - } - -/* END */ +/***************************************************************************/
+/* */
+/* ftccache.c */
+/* */
+/* The FreeType internal cache interface (body). */
+/* */
+/* Copyright 2000-2001, 2002, 2003 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_INTERNAL_MANAGER_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+#define FTC_HASH_MAX_LOAD 2
+#define FTC_HASH_MIN_LOAD 1
+#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
+
+/* this one _must_ be a power of 2! */
+#define FTC_HASH_INITIAL_SIZE 8
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE NODE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* add a new node to the head of the manager's circular MRU list */
+ static void
+ ftc_node_mru_link( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_MruNode_Prepend( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node );
+ manager->num_nodes++;
+ }
+
+
+ /* remove a node from the manager's MRU list */
+ static void
+ ftc_node_mru_unlink( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_MruNode_Remove( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node );
+ manager->num_nodes--;
+ }
+
+
+ /* move a node to the head of the manager's MRU list */
+ static void
+ ftc_node_mru_up( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_MruNode_Up( (FTC_MruNode*)&manager->nodes_list, (FTC_MruNode)node );
+ }
+
+
+ /* note that this function cannot fail. If we cannot re-size the
+ * buckets array appropriately, we simply degrade the hash table's
+ * performance !!
+ */
+ static void
+ ftc_cache_resize( FTC_Cache cache )
+ {
+ for (;;)
+ {
+ FTC_Node node, *pnode;
+ FT_UInt p = cache->p;
+ FT_UInt mask = cache->mask;
+ FT_UInt count = mask + p + 1; /* number of buckets */
+
+ /* do we need to shrink the buckets array ?
+ */
+ if ( cache->slack < 0 )
+ {
+ FTC_Node new_list = NULL;
+
+ /* try to expand the buckets array _before_ splitting
+ * the bucket lists
+ */
+ if ( p >= mask )
+ {
+ FT_Memory memory = cache->memory;
+
+ /* if we can't expand the array, leave immediately */
+ if ( FT_MEM_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
+ break;
+ }
+
+ /* split a single bucket */
+ pnode = cache->buckets + p;
+
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->hash & ( mask + 1 ) )
+ {
+ *pnode = node->link;
+ node->link = new_list;
+ new_list = node;
+ }
+ else
+ pnode = &node->link;
+ }
+
+ cache->buckets[p + mask + 1] = new_list;
+
+ cache->slack += FTC_HASH_MAX_LOAD;
+
+ if ( p >= mask )
+ {
+ cache->mask = 2 * mask + 1;
+ cache->p = 0;
+ }
+ else
+ cache->p = p + 1;
+ }
+ /* do we need to expand the buckets array ?
+ */
+ else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
+ {
+ FT_UInt old_index = p + mask;
+ FTC_Node* pold;
+
+ if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
+ break;
+
+ if ( p == 0 )
+ {
+ FT_Memory memory = cache->memory;
+
+ /* if we can't shrink the array, leave immediately */
+ if ( FT_MEM_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) )
+ break;
+
+ cache->mask >>= 1;
+ p = cache->mask;
+ }
+ else
+ p--;
+
+ pnode = cache->buckets + p;
+ while ( *pnode )
+ pnode = &(*pnode)->link;
+
+ pold = cache->buckets + old_index;
+ *pnode = *pold;
+ *pold = NULL;
+
+ cache->slack -= FTC_HASH_MAX_LOAD;
+ cache->p = p;
+ }
+ else /* the hash table is balanced */
+ break;
+ }
+ }
+
+
+
+ /* remove a node from its cache's hash table */
+ static void
+ ftc_node_hash_unlink( FTC_Node node0,
+ FTC_Cache cache )
+ {
+ FTC_Node *pnode;
+ FT_UInt idx;
+
+
+ idx = (FT_UInt)( node0->hash & cache->mask );
+ if ( idx < cache->p )
+ idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) );
+
+ pnode = cache->buckets + idx;
+
+ for (;;)
+ {
+ FTC_Node node = *pnode;
+
+ if ( node == NULL )
+ {
+ FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" ));
+ return;
+ }
+
+ if ( node == node0 )
+ break;
+
+ pnode = &(*pnode)->link;
+ }
+
+ *pnode = node0->link;
+ node0->link = NULL;
+
+ cache->slack++;
+ ftc_cache_resize( cache );
+ }
+
+
+
+ /* add a node to the "top" of its cache's hash table */
+ static void
+ ftc_node_hash_link( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FTC_Node *pnode;
+ FT_UInt idx;
+
+
+ idx = (FT_UInt)( node->hash & cache->mask );
+ if ( idx < cache->p )
+ idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
+
+ pnode = cache->buckets + idx;
+
+ node->link = *pnode;
+ *pnode = node;
+
+ cache->slack--;
+ ftc_cache_resize( cache );
+ }
+
+
+
+
+ /* remove a node from the cache manager */
+ FT_EXPORT_DEF( void )
+ ftc_node_destroy( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Cache cache;
+
+
+#ifdef FT_DEBUG_ERROR
+ /* find node's cache */
+ if ( node->cache_index >= manager->num_caches )
+ {
+ FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ cache = manager->caches[ node->cache_index ];
+
+#ifdef FT_DEBUG_ERROR
+ if ( cache == NULL )
+ {
+ FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ manager->cur_weight -= cache->clazz.node_weight( node, cache );
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* remove node from cache's hash table */
+ ftc_node_hash_unlink( node, cache );
+
+ /* now finalize it */
+ cache->clazz.node_free( node, cache );
+
+#if 0
+ /* check, just in case of general corruption :-) */
+ if ( manager->num_nodes == 0 )
+ FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n",
+ manager->num_nodes ));
+#endif
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** ABSTRACT CACHE CLASS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Cache_Init( FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+
+ cache->p = 0;
+ cache->mask = FTC_HASH_INITIAL_SIZE - 1;
+ cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
+
+ return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) );
+ }
+
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Cache_Clear( FTC_Cache cache )
+ {
+ if ( cache )
+ {
+ FTC_Manager manager = cache->manager;
+ FT_UFast i;
+ FT_UInt count;
+
+ count = cache->p + cache->mask + 1;
+
+ for ( i = 0; i < count; i++ )
+ {
+ FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
+
+
+ while ( node )
+ {
+ next = node->link;
+ node->link = NULL;
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* now finalize it */
+ manager->cur_weight -= cache->clazz.node_weight( node, cache );
+
+ cache->clazz.node_free( node, cache );
+ node = next;
+ }
+ cache->buckets[i] = NULL;
+ }
+ ftc_cache_resize( cache );
+ }
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Cache_Done( FTC_Cache cache )
+ {
+ if ( cache->memory )
+ {
+ FT_Memory memory = cache->memory;
+
+ FTC_Cache_Clear( cache );
+
+ FT_FREE( cache->buckets );
+ cache->mask = 0;
+ cache->p = 0;
+ cache->slack = 0;
+
+ cache->memory = NULL;
+ }
+ }
+
+
+
+ static void
+ ftc_cache_add( FTC_Cache cache,
+ FT_UInt32 hash,
+ FTC_Node node )
+ {
+ node->hash = hash;
+ node->cache_index = (FT_UInt16) cache->index;
+ node->ref_count = 0;
+
+ ftc_node_hash_link( node, cache );
+ ftc_node_mru_link( node, cache->manager );
+
+ {
+ FTC_Manager manager = cache->manager;
+
+ manager->cur_weight += cache->clazz.node_weight( node, cache );
+
+ if ( manager->cur_weight >= manager->max_weight )
+ {
+ node->ref_count++;
+ FTC_Manager_Compress( manager );
+ node->ref_count--;
+ }
+ }
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Cache_NewNode( FTC_Cache cache,
+ FT_UInt32 hash,
+ FT_Pointer query,
+ FTC_Node *anode )
+ {
+ FT_Error error;
+ FTC_Node node;
+
+ /*
+ * try to allocate a new cache node. Note that in case of
+ * out-of-memory error (OOM), we'll flush the cache a bit,
+ * then try again.
+ *
+ * on each try, the "tries" variable gives the number
+ * of old nodes we want to flush from the manager's global list
+ * before the next allocation attempt. it barely doubles on
+ * each iteration
+ *
+ */
+ error = cache->clazz.node_new( &node, query, cache );
+ if ( error )
+ goto FlushCache;
+
+ AddNode:
+ /* don't assume that the cache has the same number of buckets, since
+ * our allocation request might have triggered global cache flushing
+ */
+ ftc_cache_add( cache, hash, node );
+
+ Exit:
+ *anode = node;
+ return error;
+
+ FlushCache:
+ node = NULL;
+ if ( error != FT_Err_Out_Of_Memory )
+ goto Exit;
+
+ {
+ FTC_Manager manager = cache->manager;
+ FT_UInt count, tries = 1;
+
+ for (;;)
+ {
+ error = cache->clazz.node_new( &node, query, cache );
+ if ( !error )
+ break;
+
+ node = NULL;
+ if ( error != FT_Err_Out_Of_Memory )
+ goto Exit;
+
+ count = FTC_Manager_FlushN( manager, tries );
+ if ( count == 0 )
+ goto Exit;
+
+ if ( count == tries )
+ {
+ count = tries*2;
+ if ( count < tries || count > manager->num_nodes )
+ count = manager->num_nodes;
+ }
+ tries = count;
+ }
+ }
+ goto AddNode;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Cache_Lookup( FTC_Cache cache,
+ FT_UInt32 hash,
+ FT_Pointer query,
+ FTC_Node *anode )
+ {
+ FT_UFast idx;
+ FTC_Node* bucket;
+ FTC_Node* pnode;
+ FTC_Node node;
+ FT_Error error = 0;
+
+ FTC_Node_CompareFunc compare = cache->clazz.node_compare;
+
+
+ if ( cache == NULL || anode == NULL )
+ return FT_Err_Invalid_Argument;
+
+ idx = hash & cache->mask;
+ if ( idx < cache->p )
+ idx = hash & ( cache->mask * 2 + 1 );
+
+ bucket = cache->buckets + idx;
+ pnode = bucket;
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ goto NewNode;
+
+ if ( node->hash == hash && compare( node, query, cache ) )
+ break;
+
+ pnode = &node->link;
+ }
+
+ if ( node != *bucket )
+ {
+ *pnode = node->link;
+ node->link = *bucket;
+ *bucket = node;
+ }
+
+ /* move to head of MRU list */
+ {
+ FTC_Manager manager = cache->manager;
+
+ if ( node != manager->nodes_list )
+ ftc_node_mru_up( node, manager );
+ }
+ *anode = node;
+ return error;
+
+ NewNode:
+ return FTC_Cache_NewNode( cache, hash, query, anode );
+ }
+
+
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Cache_RemoveFaceID( FTC_Cache cache,
+ FTC_FaceID face_id )
+ {
+ FT_UFast i, count;
+ FTC_Manager manager = cache->manager;
+ FTC_Node free = NULL;
+
+ count = cache->p + cache->mask;
+ for ( i = 0; i < count; i++ )
+ {
+ FTC_Node* bucket = cache->buckets + i;
+ FTC_Node* pnode = bucket;
+
+ for ( ;; )
+ {
+ FTC_Node node = *pnode;
+
+ if ( node == NULL )
+ break;
+
+ if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
+ {
+ *pnode = node->link;
+ node->link = free;
+ free = node;
+ }
+ else
+ pnode = &node->link;
+ }
+ }
+
+ /* remove all nodes in the free list
+ */
+ while ( free )
+ {
+ FTC_Node node;
+
+ node = free;
+ free = node->link;
+
+ manager->cur_weight -= cache->clazz.node_weight( node, cache );
+ ftc_node_mru_unlink( node, manager );
+
+ cache->clazz.node_free( node, cache );
+
+ cache->slack ++;
+ }
+
+ ftc_cache_resize( cache );
+ }
+
+/* END */
diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c index 034ab24b3..51855983c 100644 --- a/src/cache/ftccmap.c +++ b/src/cache/ftccmap.c @@ -1,266 +1,271 @@ -/***************************************************************************/ -/* */ -/* ftccmap.c */ -/* */ -/* FreeType CharMap cache (body) */ -/* */ -/* Copyright 2000-2001, 2002, 2003 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_FREETYPE_H -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_MANAGER_H -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_DEBUG_H -#include FT_TRUETYPE_IDS_H - -#include "ftcerror.h" - -#undef FT_COMPONENT -#define FT_COMPONENT trace_cache - - /*************************************************************************/ - /* */ - /* Each FTC_CMapNode contains a simple array to map a range of character */ - /* codes to equivalent glyph indices. */ - /* */ - /* For now, the implementation is very basic: Each node maps a range of */ - /* 128 consecutive character codes to their corresponding glyph indices. */ - /* */ - /* We could do more complex things, but I don't think it is really very */ - /* useful. */ - /* */ - /*************************************************************************/ - - - /* number of glyph indices / character code per node */ -#define FTC_CMAP_INDICES_MAX 128 - - /* compute a query/node hash */ -#define FTC_CMAP_HASH( faceid, index, charcode ) \ - ( FTC_FACE_ID_HASH( faceid ) + 211*( index ) + ((char_code) / FTC_CMAP_INDICES_MAX) ) - - /* the charmap query */ - typedef struct FTC_CMapQueryRec_ - { - FTC_FaceID face_id; - FT_UInt cmap_index; - FT_UInt32 char_code; - - } FTC_CMapQueryRec, *FTC_CMapQuery; - -#define FTC_CMAP_QUERY(x) ((FTC_CMapQuery)(x)) -#define FTC_CMAP_QUERY_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code ) - - /* the cmap cache node */ - typedef struct FTC_CMapNodeRec_ - { - FTC_NodeRec node; - FTC_FaceID face_id; - FT_UInt cmap_index; - FT_UInt32 first; /* first character in node */ - FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */ - - } FTC_CMapNodeRec, *FTC_CMapNode; - -#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) ) -#define FTC_CMAP_NODE_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first ) - - /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */ - /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */ -#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 ) - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CHARMAP NODES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - /* no need for specific finalizer; we use "ftc_node_done" directly */ - - FT_CALLBACK_DEF( void ) - ftc_cmap_node_free( FTC_CMapNode node, - FTC_Cache cache ) - { - FT_Memory memory = cache->memory; - - FT_FREE( node ); - } - - - /* initialize a new cmap node */ - FT_CALLBACK_DEF( FT_Error ) - ftc_cmap_node_new( FTC_CMapNode *anode, - FTC_CMapQuery query, - FTC_Cache cache ) - { - FT_Error error; - FT_Memory memory = cache->memory; - FTC_CMapNode node; - FT_UInt nn; - - if ( !FT_NEW( node ) ) - { - node->face_id = query->face_id; - node->cmap_index = query->cmap_index; - node->first = (query->char_code / FTC_CMAP_INDICES_MAX) * - FTC_CMAP_INDICES_MAX; - - for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ ) - node->indices[nn] = FTC_CMAP_UNKNOWN; - } - - *anode = node; - return error; - } - - - /* compute the weight of a given cmap node */ - FT_CALLBACK_DEF( FT_ULong ) - ftc_cmap_node_weight( FTC_CMapNode cnode ) - { - FT_UNUSED( cnode ); - - return sizeof ( *cnode ); - } - - - /* compare a cmap node to a given query */ - FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_node_compare( FTC_CMapNode node, - FTC_CMapQuery query ) - { - if ( node->face_id == query->face_id && - node->cmap_index == query->cmap_index ) - { - FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); - - return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); - } - return 0; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_node_remove_faceid( FTC_CMapNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->face_id == face_id ); - } - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE CACHE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_TABLE_DEF - const FTC_CacheClassRec ftc_cmap_cache_class = - { - (FTC_Node_NewFunc) ftc_cmap_node_new, - (FTC_Node_WeightFunc) ftc_cmap_node_weight, - (FTC_Node_CompareFunc) ftc_cmap_node_compare, - (FTC_Node_CompareFunc) ftc_cmap_node_remove_faceid, - (FTC_Node_FreeFunc) ftc_cmap_node_free, - - sizeof ( FTC_CacheRec ), - (FTC_Cache_InitFunc) FTC_Cache_Init, - (FTC_Cache_DoneFunc) FTC_Cache_Done, - }; - - /* documentation is in ftccmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_CMapCache_New( FTC_Manager manager, - FTC_CMapCache *acache ) - { - return FTC_Manager_RegisterCache( manager, - & ftc_cmap_cache_class, - FTC_CACHE_P( acache ) ); - } - /* documentation is in ftccmap.h */ - - FT_EXPORT_DEF( FT_UInt ) - FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, - FTC_FaceID face_id, - FT_Int cmap_index, - FT_UInt32 char_code ) - { - FTC_Cache cache = FTC_CACHE( cmap_cache ); - FTC_CMapQueryRec query; - FTC_CMapNode node; - FT_Error error; - FT_UInt gindex = 0; - FT_UInt32 hash; - - - if ( !cache ) - { - FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); - return 0; - } - - query.face_id = face_id; - query.cmap_index = (FT_UInt)cmap_index; - query.char_code = char_code; - - hash = FTC_CMAP_HASH( face_id, cmap_index, char_code ); - - error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node ); - if ( error ) - goto Exit; - - FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX ); - - gindex = node->indices[ char_code - node->first ]; - if ( gindex == FTC_CMAP_UNKNOWN ) - { - FT_Face face; - - gindex = 0; - - error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face ); - if ( error ) - goto Exit; - - if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) - { - FT_CharMap old, cmap = NULL; - - old = face->charmap; - cmap = face->charmaps[ cmap_index ]; - - if (old != cmap) - FT_Set_Charmap( face, cmap ); - - gindex = FT_Get_Char_Index( face, char_code ); - - if (old != cmap) - FT_Set_Charmap( face, old ); - } - - node->indices[ char_code - node->first ] = gindex; - } - - Exit: - return gindex; - } - -/* END */ +/***************************************************************************/
+/* */
+/* ftccmap.c */
+/* */
+/* FreeType CharMap cache (body) */
+/* */
+/* Copyright 2000-2001, 2002, 2003 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_FREETYPE_H
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_MANAGER_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_TRUETYPE_IDS_H
+
+#include "ftcerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cache
+
+ /*************************************************************************/
+ /* */
+ /* Each FTC_CMapNode contains a simple array to map a range of character */
+ /* codes to equivalent glyph indices. */
+ /* */
+ /* For now, the implementation is very basic: Each node maps a range of */
+ /* 128 consecutive character codes to their corresponding glyph indices. */
+ /* */
+ /* We could do more complex things, but I don't think it is really very */
+ /* useful. */
+ /* */
+ /*************************************************************************/
+
+
+ /* number of glyph indices / character code per node */
+#define FTC_CMAP_INDICES_MAX 128
+
+ /* compute a query/node hash */
+#define FTC_CMAP_HASH( faceid, index, charcode ) \
+ ( FTC_FACE_ID_HASH( faceid ) + 211*( index ) + ((char_code) / FTC_CMAP_INDICES_MAX) )
+
+ /* the charmap query */
+ typedef struct FTC_CMapQueryRec_
+ {
+ FTC_FaceID face_id;
+ FT_UInt cmap_index;
+ FT_UInt32 char_code;
+
+ } FTC_CMapQueryRec, *FTC_CMapQuery;
+
+#define FTC_CMAP_QUERY(x) ((FTC_CMapQuery)(x))
+#define FTC_CMAP_QUERY_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->char_code )
+
+ /* the cmap cache node */
+ typedef struct FTC_CMapNodeRec_
+ {
+ FTC_NodeRec node;
+ FTC_FaceID face_id;
+ FT_UInt cmap_index;
+ FT_UInt32 first; /* first character in node */
+ FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
+
+ } FTC_CMapNodeRec, *FTC_CMapNode;
+
+#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
+#define FTC_CMAP_NODE_HASH(x) FTC_CMAP_HASH( (x)->face_id, (x)->cmap_index, (x)->first )
+
+ /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
+ /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
+#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHARMAP NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* no need for specific finalizer; we use "ftc_node_done" directly */
+
+ FT_CALLBACK_DEF( void )
+ ftc_cmap_node_free( FTC_CMapNode node,
+ FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+
+ FT_FREE( node );
+ }
+
+
+ /* initialize a new cmap node */
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_cmap_node_new( FTC_CMapNode *anode,
+ FTC_CMapQuery query,
+ FTC_Cache cache )
+ {
+ FT_Error error;
+ FT_Memory memory = cache->memory;
+ FTC_CMapNode node;
+ FT_UInt nn;
+
+ if ( !FT_NEW( node ) )
+ {
+ node->face_id = query->face_id;
+ node->cmap_index = query->cmap_index;
+ node->first = (query->char_code / FTC_CMAP_INDICES_MAX) *
+ FTC_CMAP_INDICES_MAX;
+
+ for ( nn = 0; nn < FTC_CMAP_INDICES_MAX; nn++ )
+ node->indices[nn] = FTC_CMAP_UNKNOWN;
+ }
+
+ *anode = node;
+ return error;
+ }
+
+
+ /* compute the weight of a given cmap node */
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_cmap_node_weight( FTC_CMapNode cnode )
+ {
+ FT_UNUSED( cnode );
+
+ return sizeof ( *cnode );
+ }
+
+
+ /* compare a cmap node to a given query */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_cmap_node_compare( FTC_CMapNode node,
+ FTC_CMapQuery query )
+ {
+ if ( node->face_id == query->face_id &&
+ node->cmap_index == query->cmap_index )
+ {
+ FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first );
+
+ return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
+ }
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_cmap_node_remove_faceid( FTC_CMapNode node,
+ FTC_FaceID face_id )
+ {
+ return FT_BOOL( node->face_id == face_id );
+ }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_CacheClassRec ftc_cmap_cache_class =
+ {
+ (FTC_Node_NewFunc) ftc_cmap_node_new,
+ (FTC_Node_WeightFunc) ftc_cmap_node_weight,
+ (FTC_Node_CompareFunc) ftc_cmap_node_compare,
+ (FTC_Node_CompareFunc) ftc_cmap_node_remove_faceid,
+ (FTC_Node_FreeFunc) ftc_cmap_node_free,
+
+ sizeof ( FTC_CacheRec ),
+ (FTC_Cache_InitFunc) FTC_Cache_Init,
+ (FTC_Cache_DoneFunc) FTC_Cache_Done,
+ };
+
+ /* documentation is in ftccmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_CMapCache_New( FTC_Manager manager,
+ FTC_CMapCache *acache )
+ {
+ return FTC_Manager_RegisterCache( manager,
+ & ftc_cmap_cache_class,
+ FTC_CACHE_P( acache ) );
+ }
+ /* documentation is in ftccmap.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache,
+ FTC_FaceID face_id,
+ FT_Int cmap_index,
+ FT_UInt32 char_code )
+ {
+ FTC_Cache cache = FTC_CACHE( cmap_cache );
+ FTC_CMapQueryRec query;
+ FTC_CMapNode node;
+ FT_Error error;
+ FT_UInt gindex = 0;
+ FT_UInt32 hash;
+
+
+ if ( !cache )
+ {
+ FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
+ return 0;
+ }
+
+ query.face_id = face_id;
+ query.cmap_index = (FT_UInt)cmap_index;
+ query.char_code = char_code;
+
+ hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
+
+#if 1
+ FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query,
+ node, error );
+#else
+ error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
+#endif
+ if ( error )
+ goto Exit;
+
+ FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX );
+
+ gindex = node->indices[ char_code - node->first ];
+ if ( gindex == FTC_CMAP_UNKNOWN )
+ {
+ FT_Face face;
+
+ gindex = 0;
+
+ error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face );
+ if ( error )
+ goto Exit;
+
+ if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
+ {
+ FT_CharMap old, cmap = NULL;
+
+ old = face->charmap;
+ cmap = face->charmaps[ cmap_index ];
+
+ if (old != cmap)
+ FT_Set_Charmap( face, cmap );
+
+ gindex = FT_Get_Char_Index( face, char_code );
+
+ if (old != cmap)
+ FT_Set_Charmap( face, old );
+ }
+
+ node->indices[ char_code - node->first ] = gindex;
+ }
+
+ Exit:
+ return gindex;
+ }
+
+/* END */
diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c index d0a3777c9..a09d81549 100644 --- a/src/cache/ftcglyph.c +++ b/src/cache/ftcglyph.c @@ -1,153 +1,152 @@ -/***************************************************************************/ -/* */ -/* ftcglyph.c */ -/* */ -/* FreeType Glyph Image (FT_Glyph) cache (body). */ -/* */ -/* Copyright 2000-2001 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_INTERNAL_GLYPH_H -#include FT_ERRORS_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H - -#include "ftcerror.h" - - - /* create a new chunk node, setting its cache index and ref count */ - FT_EXPORT_DEF( void ) - FTC_GNode_Init( FTC_GNode gnode, - FT_UInt gindex, - FTC_Family family ) - { - gnode->family = family; - gnode->gindex = gindex; - family->num_nodes++; - } - - - FT_EXPORT_DEF( void ) - FTC_GNode_UnselectFamily( FTC_GNode gnode, - FTC_Cache cache ) - { - FTC_Family family = gnode->family; - - gnode->family = NULL; - if ( family && --family->num_nodes <= 0 ) - { - FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family ); - } - } - - - FT_EXPORT_DEF( void ) - FTC_GNode_Done( FTC_GNode gnode, - FTC_Cache cache ) - { - /* finalize the node */ - gnode->gindex = 0; - - FTC_GNode_UnselectFamily( gnode, cache ); - } - - - FT_EXPORT_DEF( FT_Bool ) - FTC_GNode_Compare( FTC_GNode gnode, - FTC_GQuery gquery ) - { - return FT_BOOL( gnode->family == gquery->family && - gnode->gindex == gquery->gindex ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CHUNK SETS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_EXPORT_DEF( void ) - FTC_Family_Init( FTC_Family family, - FTC_Cache cache ) - { - FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS(cache); - - family->clazz = clazz->family_class; - family->num_nodes = 0; - family->cache = cache; - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_Init( FTC_GCache cache ) - { - FT_Error error; - - error = FTC_Cache_Init( FTC_CACHE(cache) ); - if ( !error ) - { - FTC_GCacheClass clazz = (FTC_GCacheClass) FTC_CACHE(cache)->org_class; - - FTC_MruList_Init( &cache->families, - clazz->family_class, - 0, /* no maximum here !! */ - cache, - FTC_CACHE(cache)->memory ); - } - return error; - } - - - FT_EXPORT_DEF( void ) - FTC_GCache_Done( FTC_GCache cache ) - { - FTC_Cache_Done( (FTC_Cache)cache ); - FTC_MruList_Done( &cache->families ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_New( FTC_Manager manager, - FTC_GCacheClass clazz, - FTC_GCache *acache ) - { - return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz, - (FTC_Cache*) acache ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_GCache_Lookup( FTC_GCache cache, - FT_UInt32 hash, - FT_UInt gindex, - FTC_GQuery query, - FTC_Node *anode ) - { - FT_Error error; - - query->gindex = gindex; - - error = FTC_MruList_Lookup( &cache->families, query, - (FTC_MruNode*) &query->family ); - if ( !error ) - error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode ); - - return error; - } - - -/* END */ +/***************************************************************************/
+/* */
+/* ftcglyph.c */
+/* */
+/* FreeType Glyph Image (FT_Glyph) cache (body). */
+/* */
+/* Copyright 2000-2001 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_INTERNAL_GLYPH_H
+#include FT_ERRORS_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+ /* create a new chunk node, setting its cache index and ref count */
+ FT_EXPORT_DEF( void )
+ FTC_GNode_Init( FTC_GNode gnode,
+ FT_UInt gindex,
+ FTC_Family family )
+ {
+ gnode->family = family;
+ gnode->gindex = gindex;
+ family->num_nodes++;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_GNode_UnselectFamily( FTC_GNode gnode,
+ FTC_Cache cache )
+ {
+ FTC_Family family = gnode->family;
+
+ gnode->family = NULL;
+ if ( family && --family->num_nodes <= 0 )
+ {
+ FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family );
+ }
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_GNode_Done( FTC_GNode gnode,
+ FTC_Cache cache )
+ {
+ /* finalize the node */
+ gnode->gindex = 0;
+
+ FTC_GNode_UnselectFamily( gnode, cache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Bool )
+ FTC_GNode_Compare( FTC_GNode gnode,
+ FTC_GQuery gquery )
+ {
+ return FT_BOOL( gnode->family == gquery->family &&
+ gnode->gindex == gquery->gindex );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_EXPORT_DEF( void )
+ FTC_Family_Init( FTC_Family family,
+ FTC_Cache cache )
+ {
+ FTC_GCacheClass clazz = FTC_CACHE__GCACHE_CLASS(cache);
+
+ family->clazz = clazz->family_class;
+ family->num_nodes = 0;
+ family->cache = cache;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_GCache_Init( FTC_GCache cache )
+ {
+ FT_Error error;
+
+ error = FTC_Cache_Init( FTC_CACHE(cache) );
+ if ( !error )
+ {
+ FTC_GCacheClass clazz = (FTC_GCacheClass) FTC_CACHE(cache)->org_class;
+
+ FTC_MruList_Init( &cache->families,
+ clazz->family_class,
+ 0, /* no maximum here !! */
+ cache,
+ FTC_CACHE(cache)->memory );
+ }
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_GCache_Done( FTC_GCache cache )
+ {
+ FTC_Cache_Done( (FTC_Cache)cache );
+ FTC_MruList_Done( &cache->families );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_GCache_New( FTC_Manager manager,
+ FTC_GCacheClass clazz,
+ FTC_GCache *acache )
+ {
+ return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz,
+ (FTC_Cache*) acache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_GCache_Lookup( FTC_GCache cache,
+ FT_UInt32 hash,
+ FT_UInt gindex,
+ FTC_GQuery query,
+ FTC_Node *anode )
+ {
+ FT_Error error;
+
+ query->gindex = gindex;
+
+ FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error );
+ if ( !error )
+ error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode );
+
+ return error;
+ }
+
+
+/* END */
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c index 769075d0a..52b9a841c 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -1,623 +1,645 @@ -/***************************************************************************/ -/* */ -/* 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_INTERNAL_MANAGER_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 ) - - - static FT_Error - ftc_scaler_lookup_size( FTC_Manager manager, - FTC_Scaler scaler, - FT_Size *asize ) - { - FT_Face face; - FT_Size size = NULL; - FT_Error error; - - error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); - if ( error ) goto Exit; - - error = FT_New_Size( face, &size ); - if ( error ) goto Exit; - - FT_Activate_Size( size ); - - if ( scaler->pixel ) - error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height ); - else - error = FT_Set_Char_Size( face, scaler->width, scaler->height, - scaler->x_res, scaler->y_res ); - if ( error ) - { - FT_Done_Size( size ); - size = NULL; - } - - Exit: - *asize = size; - return error; - } - - - typedef struct FTC_SizeNodeRec_ - { - FTC_MruNodeRec node; - FT_Size size; - FTC_ScalerRec scaler; - - } FTC_SizeNodeRec, *FTC_SizeNode; - - - FT_CALLBACK_DEF( void ) - ftc_size_node_done( FTC_SizeNode node ) - { - FT_Size size = node->size; - - if ( size ) - FT_Done_Size( size ); - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_size_node_compare( FTC_SizeNode node, - FTC_Scaler scaler ) - { - FTC_Scaler scaler0 = &node->scaler; - - return FTC_SCALER_COMPARE( scaler0, scaler ); - } - - - - FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_init( FTC_SizeNode node, - FTC_Scaler scaler, - FTC_Manager manager ) - { - node->scaler = scaler[0]; - - return ftc_scaler_lookup_size( manager, scaler, &node->size ); - } - - - FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_reset( FTC_SizeNode node, - FTC_Scaler scaler, - FTC_Manager manager ) - { - FT_Done_Size( node->size ); - - node->scaler = scaler[0]; - - return ftc_scaler_lookup_size( manager, scaler, &node->size ); - } - - - static const FTC_MruListClassRec ftc_size_list_class = - { - sizeof( FTC_SizeNodeRec ), - (FTC_MruNode_CompareFunc) ftc_size_node_compare, - (FTC_MruNode_InitFunc) ftc_size_node_init, - (FTC_MruNode_ResetFunc) ftc_size_node_reset, - (FTC_MruNode_DoneFunc) ftc_size_node_done - }; - - - /* helper function used by ftc_face_node_done */ - static FT_Bool - ftc_size_node_compare_faceid( FTC_SizeNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->scaler.face_id == face_id ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_LookupSize( FTC_Manager manager, - FTC_Scaler scaler, - FT_Size *asize ) - { - FT_Error error; - FTC_SizeNode node; - - - if ( asize == NULL ) - return FTC_Err_Bad_Argument; - - *asize = NULL; - - if ( !manager ) - return FTC_Err_Invalid_Cache_Handle; - - error = FTC_MruList_Lookup( &manager->sizes, - scaler, - (FTC_MruNode*) &node ); - if ( !error ) - *asize = node->size; - - return error; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FACE MRU IMPLEMENTATION *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - typedef struct FTC_FaceNodeRec_ - { - FTC_MruNodeRec node; - FTC_FaceID face_id; - FT_Face face; - - } FTC_FaceNodeRec, *FTC_FaceNode; - - - - FT_CALLBACK_DEF( FT_Error ) - ftc_face_node_init( FTC_FaceNode node, - FTC_FaceID face_id, - FTC_Manager manager ) - { - FT_Error error; - - node->face_id = face_id; - - 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; - } - - - FT_CALLBACK_DEF( void ) - ftc_face_node_done( FTC_FaceNode node, - FTC_Manager manager ) - { - /* we must begin by removing all scalers for the target face */ - /* from the manager's list */ - FTC_MruList_RemoveSelection( - & manager->sizes, - (FTC_MruNode_CompareFunc) ftc_size_node_compare_faceid, - node->face_id ); - - /* all right, we can discard the face now */ - FT_Done_Face( node->face ); - node->face = NULL; - node->face_id = NULL; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_face_node_compare( FTC_FaceNode node, - FTC_FaceID face_id ) - { - return FT_BOOL( node->face_id == face_id ); - } - - - static const FTC_MruListClassRec ftc_face_list_class = - { - sizeof( FTC_FaceNodeRec), - - (FTC_MruNode_CompareFunc) ftc_face_node_compare, - (FTC_MruNode_InitFunc) ftc_face_node_init, - (FTC_MruNode_ResetFunc) NULL, - (FTC_MruNode_DoneFunc) ftc_face_node_done - }; - - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_Manager_LookupFace( 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 = FTC_MruList_Lookup( &manager->faces, - face_id, - (FTC_MruNode*) &node ); - if ( !error ) - *aface = node->face; - - return error; - } - - - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** 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; - - manager->library = library; - manager->memory = memory; - manager->max_weight = max_bytes; - - manager->request_face = requester; - manager->request_data = req_data; - - FTC_MruList_Init( &manager->faces, - &ftc_face_list_class, - max_faces, - manager, - memory ); - - FTC_MruList_Init( &manager->sizes, - &ftc_size_list_class, - max_sizes, - manager, - memory ); - - *amanager = manager; - - Exit: - 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->memory; - - /* now discard all caches */ - for (idx = manager->num_caches; idx-- > 0; ) - { - FTC_Cache cache = manager->caches[idx]; - - if ( cache ) - { - cache->clazz.cache_done( cache ); - FT_FREE( cache ); - manager->caches[idx] = NULL; - } - } - manager->num_caches = 0; - - /* discard faces and sizes */ - FTC_MruList_Done( &manager->sizes ); - FTC_MruList_Done( &manager->faces ); - - manager->library = NULL; - manager->memory = NULL; - - FT_FREE( manager ); - } - - - /* documentation is in ftcache.h */ - - FT_EXPORT_DEF( void ) - FTC_Manager_Reset( FTC_Manager manager ) - { - if ( manager ) - { - FTC_MruList_Reset( &manager->sizes ); - FTC_MruList_Reset( &manager->faces ); - } - /* 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_Cache cache = manager->caches[ node->cache_index ]; - - if ( (FT_UInt)node->cache_index >= manager->num_caches ) - FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n", - node->cache_index )); - else - { - weight += cache->clazz.node_weight( node, cache ); - } - - node = FTC_NODE__NEXT(node); - - } 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 = FTC_NODE__NEXT(node); - - } 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 = FTC_NODE__PREV(first); - do - { - FTC_Node prev; - - - prev = ( node == first ) ? NULL : FTC_NODE__PREV(node); - - 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_RegisterCache( FTC_Manager manager, - FTC_CacheClass clazz, - FTC_Cache *acache ) - { - FT_Error error = FTC_Err_Invalid_Argument; - FTC_Cache cache = NULL; - - - if ( manager && clazz && acache ) - { - FT_Memory memory = manager->memory; - - if ( manager->num_caches >= FTC_MAX_CACHES ) - { - error = FTC_Err_Too_Many_Caches; - FT_ERROR(( "%s: too many registered caches\n", - "FTC_Manager_Register_Cache" )); - goto Exit; - } - - if ( !FT_ALLOC( cache, clazz->cache_size ) ) - { - cache->manager = manager; - cache->memory = memory; - cache->clazz = clazz[0]; - cache->org_class = clazz; - - /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */ - /* IF IT IS NOT SET CORRECTLY */ - cache->index = manager->num_caches; - - error = clazz->cache_init( cache ); - if ( error ) - { - clazz->cache_done( cache ); - FT_FREE( cache ); - goto Exit; - } - - manager->caches[ manager->num_caches++ ] = cache; - } - } - - Exit: - *acache = cache; - return error; - } - - - FT_EXPORT_DEF( FT_UInt ) - FTC_Manager_FlushN( FTC_Manager manager, - FT_UInt count ) - { - FTC_Node first = manager->nodes_list; - FTC_Node node; - FT_UInt result; - - /* try to remove "count" nodes from the list */ - if ( first == NULL ) /* empty list! */ - return 0; - - /* go to last node - it's a circular list */ - node = FTC_NODE__PREV(first); - for ( result = 0; result < count; ) - { - FTC_Node prev = FTC_NODE__PREV(node); - - - /* don't touch locked nodes */ - if ( node->ref_count <= 0 ) - { - ftc_node_destroy( node, manager ); - result++; - } - - if ( prev == manager->nodes_list ) - break; - - node = prev; - } - return result; - } - - - FT_EXPORT_DEF( void ) - FTC_Manager_RemoveFaceID( FTC_Manager manager, - FTC_FaceID face_id ) - { - FT_UInt nn; - - /* this will remove all FTC_SizeNode that correspond to - * the face_id as well - */ - FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id ); - - for ( nn = 0; nn < manager->num_caches; nn++ ) - FTC_Cache_RemoveFaceID( manager->caches[nn], face_id ); - } - - - /* documentation is in ftcmanag.h */ - - FT_EXPORT_DEF( void ) - FTC_Node_Unref( FTC_Node node, - FTC_Manager manager ) - { - if ( node && (FT_UInt)node->cache_index < manager->num_caches ) - node->ref_count--; - } - - -/* END */ +/***************************************************************************/
+/* */
+/* 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_INTERNAL_MANAGER_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 )
+
+
+ static FT_Error
+ ftc_scaler_lookup_size( FTC_Manager manager,
+ FTC_Scaler scaler,
+ FT_Size *asize )
+ {
+ FT_Face face;
+ FT_Size size = NULL;
+ FT_Error error;
+
+ error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
+ if ( error ) goto Exit;
+
+ error = FT_New_Size( face, &size );
+ if ( error ) goto Exit;
+
+ FT_Activate_Size( size );
+
+ if ( scaler->pixel )
+ error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
+ else
+ error = FT_Set_Char_Size( face, scaler->width, scaler->height,
+ scaler->x_res, scaler->y_res );
+ if ( error )
+ {
+ FT_Done_Size( size );
+ size = NULL;
+ }
+
+ Exit:
+ *asize = size;
+ return error;
+ }
+
+
+ typedef struct FTC_SizeNodeRec_
+ {
+ FTC_MruNodeRec node;
+ FT_Size size;
+ FTC_ScalerRec scaler;
+
+ } FTC_SizeNodeRec, *FTC_SizeNode;
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_size_node_done( FTC_SizeNode node )
+ {
+ FT_Size size = node->size;
+
+ if ( size )
+ FT_Done_Size( size );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_size_node_compare( FTC_SizeNode node,
+ FTC_Scaler scaler )
+ {
+ FTC_Scaler scaler0 = &node->scaler;
+
+ return FTC_SCALER_COMPARE( scaler0, scaler );
+ }
+
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_size_node_init( FTC_SizeNode node,
+ FTC_Scaler scaler,
+ FTC_Manager manager )
+ {
+ node->scaler = scaler[0];
+
+ return ftc_scaler_lookup_size( manager, scaler, &node->size );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_size_node_reset( FTC_SizeNode node,
+ FTC_Scaler scaler,
+ FTC_Manager manager )
+ {
+ FT_Done_Size( node->size );
+
+ node->scaler = scaler[0];
+
+ return ftc_scaler_lookup_size( manager, scaler, &node->size );
+ }
+
+
+ static const FTC_MruListClassRec ftc_size_list_class =
+ {
+ sizeof( FTC_SizeNodeRec ),
+ (FTC_MruNode_CompareFunc) ftc_size_node_compare,
+ (FTC_MruNode_InitFunc) ftc_size_node_init,
+ (FTC_MruNode_ResetFunc) ftc_size_node_reset,
+ (FTC_MruNode_DoneFunc) ftc_size_node_done
+ };
+
+
+ /* helper function used by ftc_face_node_done */
+ static FT_Bool
+ ftc_size_node_compare_faceid( FTC_SizeNode node,
+ FTC_FaceID face_id )
+ {
+ return FT_BOOL( node->scaler.face_id == face_id );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_LookupSize( FTC_Manager manager,
+ FTC_Scaler scaler,
+ FT_Size *asize )
+ {
+ FT_Error error;
+ FTC_SizeNode node;
+
+
+ if ( asize == NULL )
+ return FTC_Err_Bad_Argument;
+
+ *asize = NULL;
+
+ if ( !manager )
+ return FTC_Err_Invalid_Cache_Handle;
+
+ /* we break encapsulation for the sake of speed */
+
+ error = 0;
+ FTC_MRULIST_LOOP( &manager->sizes, node )
+ {
+ FTC_Scaler scaler0 = &node->scaler;
+
+ if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
+ goto Found;
+ }
+ FTC_MRULIST_LOOP_END();
+
+ error = FTC_MruList_New( &manager->sizes, scaler, (FTC_MruNode*)&node );
+
+ Found:
+ if ( !error )
+ *asize = node->size;
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FACE MRU IMPLEMENTATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct FTC_FaceNodeRec_
+ {
+ FTC_MruNodeRec node;
+ FTC_FaceID face_id;
+ FT_Face face;
+
+ } FTC_FaceNodeRec, *FTC_FaceNode;
+
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_face_node_init( FTC_FaceNode node,
+ FTC_FaceID face_id,
+ FTC_Manager manager )
+ {
+ FT_Error error;
+
+ node->face_id = face_id;
+
+ 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;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_face_node_done( FTC_FaceNode node,
+ FTC_Manager manager )
+ {
+ /* we must begin by removing all scalers for the target face */
+ /* from the manager's list */
+ FTC_MruList_RemoveSelection(
+ & manager->sizes,
+ (FTC_MruNode_CompareFunc) ftc_size_node_compare_faceid,
+ node->face_id );
+
+ /* all right, we can discard the face now */
+ FT_Done_Face( node->face );
+ node->face = NULL;
+ node->face_id = NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_face_node_compare( FTC_FaceNode node,
+ FTC_FaceID face_id )
+ {
+ return FT_BOOL( node->face_id == face_id );
+ }
+
+
+ static const FTC_MruListClassRec ftc_face_list_class =
+ {
+ sizeof( FTC_FaceNodeRec),
+
+ (FTC_MruNode_CompareFunc) ftc_face_node_compare,
+ (FTC_MruNode_InitFunc) ftc_face_node_init,
+ (FTC_MruNode_ResetFunc) NULL,
+ (FTC_MruNode_DoneFunc) ftc_face_node_done
+ };
+
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_LookupFace( 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;
+
+ /* we break encapsulation for the sake of speed */
+
+ error = 0;
+ FTC_MRULIST_LOOP( &manager->faces, node )
+ {
+ if ( node->face_id == face_id )
+ goto Found;
+ }
+ FTC_MRULIST_LOOP_END();
+
+ error = FTC_MruList_New( &manager->faces, face_id, (FTC_MruNode*)&node );
+
+ Found:
+ if ( !error )
+ *aface = node->face;
+
+ return error;
+ }
+
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** 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;
+
+ manager->library = library;
+ manager->memory = memory;
+ manager->max_weight = max_bytes;
+
+ manager->request_face = requester;
+ manager->request_data = req_data;
+
+ FTC_MruList_Init( &manager->faces,
+ &ftc_face_list_class,
+ max_faces,
+ manager,
+ memory );
+
+ FTC_MruList_Init( &manager->sizes,
+ &ftc_size_list_class,
+ max_sizes,
+ manager,
+ memory );
+
+ *amanager = manager;
+
+ Exit:
+ 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->memory;
+
+ /* now discard all caches */
+ for (idx = manager->num_caches; idx-- > 0; )
+ {
+ FTC_Cache cache = manager->caches[idx];
+
+ if ( cache )
+ {
+ cache->clazz.cache_done( cache );
+ FT_FREE( cache );
+ manager->caches[idx] = NULL;
+ }
+ }
+ manager->num_caches = 0;
+
+ /* discard faces and sizes */
+ FTC_MruList_Done( &manager->sizes );
+ FTC_MruList_Done( &manager->faces );
+
+ manager->library = NULL;
+ manager->memory = NULL;
+
+ FT_FREE( manager );
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Reset( FTC_Manager manager )
+ {
+ if ( manager )
+ {
+ FTC_MruList_Reset( &manager->sizes );
+ FTC_MruList_Reset( &manager->faces );
+ }
+ /* 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_Cache cache = manager->caches[ node->cache_index ];
+
+ if ( (FT_UInt)node->cache_index >= manager->num_caches )
+ FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n",
+ node->cache_index ));
+ else
+ {
+ weight += cache->clazz.node_weight( node, cache );
+ }
+
+ node = FTC_NODE__NEXT(node);
+
+ } 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 = FTC_NODE__NEXT(node);
+
+ } 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 = FTC_NODE__PREV(first);
+ do
+ {
+ FTC_Node prev;
+
+
+ prev = ( node == first ) ? NULL : FTC_NODE__PREV(node);
+
+ 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_RegisterCache( FTC_Manager manager,
+ FTC_CacheClass clazz,
+ FTC_Cache *acache )
+ {
+ FT_Error error = FTC_Err_Invalid_Argument;
+ FTC_Cache cache = NULL;
+
+
+ if ( manager && clazz && acache )
+ {
+ FT_Memory memory = manager->memory;
+
+ if ( manager->num_caches >= FTC_MAX_CACHES )
+ {
+ error = FTC_Err_Too_Many_Caches;
+ FT_ERROR(( "%s: too many registered caches\n",
+ "FTC_Manager_Register_Cache" ));
+ goto Exit;
+ }
+
+ if ( !FT_ALLOC( cache, clazz->cache_size ) )
+ {
+ cache->manager = manager;
+ cache->memory = memory;
+ cache->clazz = clazz[0];
+ cache->org_class = clazz;
+
+ /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
+ /* IF IT IS NOT SET CORRECTLY */
+ cache->index = manager->num_caches;
+
+ error = clazz->cache_init( cache );
+ if ( error )
+ {
+ clazz->cache_done( cache );
+ FT_FREE( cache );
+ goto Exit;
+ }
+
+ manager->caches[ manager->num_caches++ ] = cache;
+ }
+ }
+
+ Exit:
+ *acache = cache;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_UInt )
+ FTC_Manager_FlushN( FTC_Manager manager,
+ FT_UInt count )
+ {
+ FTC_Node first = manager->nodes_list;
+ FTC_Node node;
+ FT_UInt result;
+
+ /* try to remove "count" nodes from the list */
+ if ( first == NULL ) /* empty list! */
+ return 0;
+
+ /* go to last node - it's a circular list */
+ node = FTC_NODE__PREV(first);
+ for ( result = 0; result < count; )
+ {
+ FTC_Node prev = FTC_NODE__PREV(node);
+
+
+ /* don't touch locked nodes */
+ if ( node->ref_count <= 0 )
+ {
+ ftc_node_destroy( node, manager );
+ result++;
+ }
+
+ if ( prev == manager->nodes_list )
+ break;
+
+ node = prev;
+ }
+ return result;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_RemoveFaceID( FTC_Manager manager,
+ FTC_FaceID face_id )
+ {
+ FT_UInt nn;
+
+ /* this will remove all FTC_SizeNode that correspond to
+ * the face_id as well
+ */
+ FTC_MruList_RemoveSelection( &manager->faces, NULL, face_id );
+
+ for ( nn = 0; nn < manager->num_caches; nn++ )
+ FTC_Cache_RemoveFaceID( manager->caches[nn], face_id );
+ }
+
+
+ /* documentation is in ftcmanag.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Node_Unref( FTC_Node node,
+ FTC_Manager manager )
+ {
+ if ( node && (FT_UInt)node->cache_index < manager->num_caches )
+ node->ref_count--;
+ }
+
+
+/* END */
|