From 040616a116af7cd5addc879a67017b051f9e760f Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 19 Dec 2003 21:23:58 +0000 Subject: [PATCH] new version of the cache sub-system - still under debugging --- include/freetype/cache/ftccache.h | 239 +++------ include/freetype/cache/ftcglyph.h | 250 ++++++---- include/freetype/cache/ftcimage.h | 303 ++---------- include/freetype/cache/ftcmanag.h | 156 ++---- include/freetype/cache/ftcmru.h | 143 ++++++ include/freetype/cache/ftcsbits.h | 260 ++-------- include/freetype/cache/ftlru.h | 208 -------- include/freetype/config/ftheader.h | 23 +- include/freetype/config/ftoption.h | 6 +- include/freetype/ftcache.h | 439 ++++++++++++++-- include/freetype/ftstroke.h | 374 +++++++++++++- src/autofit/afhints.c | 4 +- src/autofit/afhints.h | 4 + src/autofit/aflatin.c | 5 +- src/autofit/aftypes.h | 30 +- src/base/ftstroke.c | 84 +++- src/cache/Jamfile | 10 +- src/cache/ftcache.c | 6 +- src/cache/ftcbasic.c | 380 ++++++++++++++ src/cache/ftccache.c | 770 +++++++++++------------------ src/cache/ftccmap.c | 402 ++++----------- src/cache/ftcglyph.c | 117 +++-- src/cache/ftcimage.c | 338 +------------ src/cache/ftcmanag.c | 625 +++++++++-------------- src/cache/ftcmru.c | 204 ++++++++ src/cache/ftcsbits.c | 551 ++++++--------------- src/cache/ftlru.c | 390 --------------- src/cache/rules.mk | 6 +- 28 files changed, 2883 insertions(+), 3444 deletions(-) create mode 100644 include/freetype/cache/ftcmru.h delete mode 100644 include/freetype/cache/ftlru.h create mode 100644 src/cache/ftcbasic.c create mode 100644 src/cache/ftcmru.c delete mode 100644 src/cache/ftlru.c diff --git a/include/freetype/cache/ftccache.h b/include/freetype/cache/ftccache.h index 701b13eb0..60191bc00 100644 --- a/include/freetype/cache/ftccache.h +++ b/include/freetype/cache/ftccache.h @@ -20,9 +20,6 @@ #define __FTCCACHE_H__ -/* define to allow cache lookup inlining */ -#define FTC_CACHE_USE_INLINE - FT_BEGIN_HEADER @@ -30,14 +27,7 @@ FT_BEGIN_HEADER typedef struct FTC_CacheRec_* FTC_Cache; /* handle to cache class */ - typedef const struct FTC_Cache_ClassRec_* FTC_Cache_Class; - - /* handle to cache node family */ - typedef struct FTC_FamilyRec_* FTC_Family; - - /* handle to cache root query */ - typedef struct FTC_QueryRec_* FTC_Query; - + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; /*************************************************************************/ /*************************************************************************/ @@ -66,7 +56,7 @@ FT_BEGIN_HEADER FTC_Node mru_prev; /* circular mru list pointer */ FTC_Node link; /* used for hashing */ FT_UInt32 hash; /* used for hashing too */ - FT_UShort fam_index; /* index of family the node belongs to */ + FT_UShort cache_index; /* index of cache the node belongs to */ FT_Short ref_count; /* reference count for this node */ } FTC_NodeRec; @@ -83,108 +73,72 @@ FT_BEGIN_HEADER /* cache sub-system internals. */ /* */ - /* can be used as a FTC_Node_DoneFunc */ - FT_EXPORT( void ) - ftc_node_done( FTC_Node node, - FTC_Cache cache ); - /* reserved for manager's use */ FT_EXPORT( void ) ftc_node_destroy( FTC_Node node, FTC_Manager manager ); - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE QUERY DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* A structure modelling a cache node query. The following fields must */ - /* all be set by the @FTC_Family_CompareFunc method of a cache's family */ - /* list. */ - /* */ - typedef struct FTC_QueryRec_ - { - FTC_Family family; - FT_UFast hash; - - } FTC_QueryRec; - - -#define FTC_QUERY( x ) ( (FTC_Query)(x) ) -#define FTC_QUERY_P( x ) ( (FTC_Query*)(x) ) - /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** CACHE FAMILY DEFINITIONS *****/ + /***** CACHE DEFINITIONS *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ - typedef struct FTC_FamilyRec_ - { - FT_LruNodeRec lru; - FTC_Cache cache; - FT_UInt num_nodes; - FT_UInt fam_index; + /* initialize a new cache node */ + typedef FT_Error (*FTC_Node_NewFunc)( FTC_Node *pnode, + FT_Pointer query, + FTC_Cache cache ); - } FTC_FamilyRec; + typedef FT_ULong (*FTC_Node_WeightFunc)( FTC_Node node, + FTC_Cache cache ); + /* compare a node to a given key pair */ + typedef FT_Bool (*FTC_Node_CompareFunc)( FTC_Node node, + FT_Pointer key, + FTC_Cache cache ); -#define FTC_FAMILY( x ) ( (FTC_Family)(x) ) -#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) ) + typedef void (*FTC_Node_FreeFunc)( FTC_Node node, + FTC_Cache cache ); - /*************************************************************************/ - /* */ - /* These functions are exported so that they can be called from */ - /* user-provided cache classes; otherwise, they are really part of the */ - /* cache sub-system internals. */ - /* */ + typedef FT_Error (*FTC_Cache_InitFunc)( FTC_Cache cache ); - /* must be called by any FTC_Node_InitFunc routine */ - FT_EXPORT( FT_Error ) - ftc_family_init( FTC_Family family, - FTC_Query query, - FTC_Cache cache ); + typedef void (*FTC_Cache_DoneFunc)( FTC_Cache cache ); - /* can be used as a FTC_Family_DoneFunc; otherwise, must be called */ - /* by any family finalizer function */ - FT_EXPORT( void ) - ftc_family_done( FTC_Family family ); + typedef struct FTC_CacheClassRec_ + { + FTC_Node_NewFunc node_new; + FTC_Node_WeightFunc node_weight; + FTC_Node_CompareFunc node_compare; + FTC_Node_CompareFunc node_remove_faceid; + FTC_Node_FreeFunc node_free; + FT_UInt cache_size; + FTC_Cache_InitFunc cache_init; + FTC_Cache_DoneFunc cache_done; - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ + } FTC_CacheClassRec; /* each cache really implements a dynamic hash table to manage its nodes */ typedef struct FTC_CacheRec_ { - FTC_Manager manager; - FT_Memory memory; - FTC_Cache_Class clazz; - - FT_UInt cache_index; /* in manager's table */ - FT_Pointer cache_data; /* used by cache node methods */ - FT_UFast p; FT_UFast mask; FT_Long slack; FTC_Node* buckets; - FT_LruList_ClassRec family_class; - FT_LruList families; + FTC_CacheClassRec clazz; /* local copy, for speed */ + + FTC_Manager manager; + FT_Memory memory; + FT_UInt index; /* in manager's table */ + + FTC_CacheClass org_class; /* original class pointer */ } FTC_CacheRec; @@ -193,105 +147,38 @@ FT_BEGIN_HEADER #define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) - /* initialize a given cache */ - typedef FT_Error - (*FTC_Cache_InitFunc)( FTC_Cache cache ); - - /* clear a cache */ - typedef void - (*FTC_Cache_ClearFunc)( FTC_Cache cache ); - - /* finalize a given cache */ - typedef void - (*FTC_Cache_DoneFunc)( FTC_Cache cache ); - - - typedef FT_Error - (*FTC_Family_InitFunc)( FTC_Family family, - FTC_Query query, - FTC_Cache cache ); - - typedef FT_Int - (*FTC_Family_CompareFunc)( FTC_Family family, - FTC_Query query ); - - typedef void - (*FTC_Family_DoneFunc)( FTC_Family family, - FTC_Cache cache ); - - /* initialize a new cache node */ - typedef FT_Error - (*FTC_Node_InitFunc)( FTC_Node node, - FT_Pointer type, - FTC_Cache cache ); - - /* compute the weight of a given cache node */ - typedef FT_ULong - (*FTC_Node_WeightFunc)( FTC_Node node, - FTC_Cache cache ); - - /* compare a node to a given key pair */ - typedef FT_Bool - (*FTC_Node_CompareFunc)( FTC_Node node, - FT_Pointer key, - FTC_Cache cache ); - - /* finalize a given cache node */ - typedef void - (*FTC_Node_DoneFunc)( FTC_Node node, - FTC_Cache cache ); - - - typedef struct FTC_Cache_ClassRec_ - { - FT_UInt cache_size; - FTC_Cache_InitFunc cache_init; - FTC_Cache_ClearFunc cache_clear; - FTC_Cache_DoneFunc cache_done; - - FT_UInt family_size; - FTC_Family_InitFunc family_init; - FTC_Family_CompareFunc family_compare; - FTC_Family_DoneFunc family_done; - - FT_UInt node_size; - FTC_Node_InitFunc node_init; - FTC_Node_WeightFunc node_weight; - FTC_Node_CompareFunc node_compare; - FTC_Node_DoneFunc node_done; - - } FTC_Cache_ClassRec; - - - /* */ - - - /*************************************************************************/ - /* */ - /* These functions are exported so that they can be called from */ - /* user-provided cache classes; otherwise, they are really part of the */ - /* cache sub-system internals. */ - /* */ - - /* can be used directly as FTC_Cache_DoneFunc(), or called by custom */ - /* cache finalizers */ - FT_EXPORT( void ) - ftc_cache_done( FTC_Cache cache ); + /* default cache initialize */ + FT_EXPORT( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); - /* can be used directly as FTC_Cache_ClearFunc(), or called by custom */ - /* cache clear routines */ + /* default cache finalizer */ FT_EXPORT( void ) - ftc_cache_clear( FTC_Cache cache ); + FTC_Cache_Done( FTC_Cache cache ); - /* initalize the hash table within the cache */ + /* call this function to lookup the cache. if no corresponding + * node is found, a new one is automatically created. This function + * is capable of flushing the cache adequately to make room for the + * new cache object. + */ FT_EXPORT( FT_Error ) - ftc_cache_init( FTC_Cache cache ); - - /* can be called when the key's hash value has been computed */ - FT_EXPORT( FT_Error ) - ftc_cache_lookup( FTC_Cache cache, - FTC_Query query, - FTC_Node *anode ); + FTC_Cache_Lookup( FTC_Cache cache, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); + + /* remove all nodes that relate to a given face_id. This is useful + * when un-installing fonts. Note that if a cache node relates to + * the face_id, but is locked (i.e. has 'ref_count > 0'), the node + * will _not_ be destroyed, but its internal face_id reference will + * be modified. + * + * the end result will be that the node will never come back + * in further lookup requests, and will be flushed on demand from + * the cache normally when its reference count reaches 0 + */ + FT_EXPORT( void ) + FTC_Cache_RemoveFaceID( FTC_Cache cache, + FTC_FaceID face_id ); /* */ diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h index ee72c3331..3b7510d06 100644 --- a/include/freetype/cache/ftcglyph.h +++ b/include/freetype/cache/ftcglyph.h @@ -16,13 +16,84 @@ /***************************************************************************/ + /* + * + * FTC_GCache is an _abstract_ cache object optimized to store glyph + * data. It works as follows: + * + * - it manages FTC_GNode objects. Each one of them can hold one or more + * glyph "items". Item types are not specified in the FTC_GCache but in + * classes that extend it + * + * - glyph attributes, like face_id, character size, render mode, etc.. + * can be grouped in abstract "glyph families". This avoids storing + * the attributes within the FTC_GCache, since it is likely that many + * FTC_GNodes will belong to the same family in typical uses + * + * - each FTC_GNode is thus a FTC_Node with two additionnal fields: + * + * * gindex :: a glyph index, or the first index in a glyph range + * * family :: a pointer to a glyph "family" + * + * - Family types are not fully specific in the FTC_Family type, but + * by classes that extend it. + * + * Note that both FTC_ImageCache and FTC_SBitCache extend FTC_GCache. They + * share an FTC_Family sub-class called FTC_BasicFamily which is used to + * store the following data: face_id, pixel/point sizes, load flags. + * for more details, see the file "src/cache/ftcbasic.c" + * + * Client applications can extend FTC_GNode with their own FTC_GNode + * and FTC_Family sub-classes to implement more complex caches (e.g. + * handling automatic synthetis, like obliquing & emboldening, colored + * glyphs, etc...) + * + * See also the FTC_ICache & FTC_SCache classes in "ftcimage.h" and + * "ftcsbits.h", which both extend FTC_GCache with additionnal + * optimizations. + * + * + * a typical FTC_GCache implementation must provide at least the following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods, i.e: + * my_node_new ( must call FTC_GNode_Init ) + * my_node_free ( must call FTC_GNode_Done ) + * my_node_compare ( must call FTC_GNode_Compare ) + * my_node_remove_faceid ( must call ftc_gnode_unselect in case + * of match ) + * + * + * - FTC_Family sub-class, e.g. MyFamily, with relevant methods, e.g.: + * my_family_compare + * my_family_init + * my_family_reset (optional) + * my_family_done + * + * - FTC_GQuery sub-class, e.g. MyQuery, to hold cache-specific query + * data. + * + * - provide constant structures for a FTC_GNodeClass + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New + * + * - implement MyCacheLookup with a call to FTC_GCache_Lookup. This + * function will automatically: + * + * - search for the corresponding family in the cache, or create + * a new one if necessary. put it in FTC_GQUERY(myquery).family + * + * - call FTC_Cache_Lookup + * + * if it returns NULL, you should create a new node, then call + * ftc_cache_add as usual. + */ + /*************************************************************************/ /* */ /* Important: The functions defined in this file are only used to */ /* implement an abstract glyph cache class. You need to */ /* provide additional logic to implement a complete cache. */ - /* For example, see `ftcimage.h' and `ftcimage.c' which */ - /* implement a FT_Glyph cache based on this code. */ /* */ /*************************************************************************/ @@ -47,98 +118,63 @@ #include -#include FT_CACHE_H -#include FT_CACHE_MANAGER_H +#include FT_CACHE_INTERNAL_MANAGER_H FT_BEGIN_HEADER - /* each glyph set is characterized by a "glyph set type" which must be */ - /* defined by sub-classes */ - typedef struct FTC_GlyphFamilyRec_* FTC_GlyphFamily; - - /* handle to a glyph cache node */ - typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode; - - - /* size should be 24 + chunk size on 32-bit machines; */ - /* note that the node's hash is ((gfam->hash << 16) | glyph_index) -- */ - /* this _must_ be set properly by the glyph node initializer */ - /* */ - typedef struct FTC_GlyphNodeRec_ + /* + * we can group glyph in "families". Each family correspond to a + * given face id, character size, transform, etc... + * + * families are implemented as MRU list nodes. They are reference-counted + */ + + typedef struct FTC_FamilyRec_ { - FTC_NodeRec node; - FT_UShort item_count; - FT_UShort item_start; + FTC_MruNode mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; - } FTC_GlyphNodeRec; +#define FTC_FAMILY(x) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) -#define FTC_GLYPH_NODE( x ) ( (FTC_GlyphNode)(x) ) -#define FTC_GLYPH_NODE_P( x ) ( (FTC_GlyphNode*)(x) ) - - - typedef struct FTC_GlyphQueryRec_ + typedef struct FTC_GNodeRec_ { - FTC_QueryRec query; - FT_UInt gindex; + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; - } FTC_GlyphQueryRec, *FTC_GlyphQuery; + } FTC_GNodeRec, *FTC_GNode; +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) -#define FTC_GLYPH_QUERY( x ) ( (FTC_GlyphQuery)(x) ) - - /* a glyph set is used to categorize glyphs of a given type */ - typedef struct FTC_GlyphFamilyRec_ + typedef struct FTC_GQueryRec_ { - FTC_FamilyRec family; - FT_UInt32 hash; - FT_UInt item_total; /* total number of glyphs in family */ - FT_UInt item_count; /* number of glyph items per node */ - - } FTC_GlyphFamilyRec; + FT_UInt gindex; + FTC_Family family; + } FTC_GQueryRec, *FTC_GQuery; -#define FTC_GLYPH_FAMILY( x ) ( (FTC_GlyphFamily)(x) ) -#define FTC_GLYPH_FAMILY_P( x ) ( (FTC_GlyphFamily*)(x) ) +#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) ) -#define FTC_GLYPH_FAMILY_MEMORY( x ) FTC_FAMILY(x)->cache->memory /* each glyph node contains a 'chunk' of glyph items; */ /* translate a glyph index into a chunk index */ -#define FTC_GLYPH_FAMILY_CHUNK( gfam, gindex ) \ - ( ( gindex ) / FTC_GLYPH_FAMILY( gfam )->item_count ) +#define FTC_FAMILY_CHUNK( gfam, gindex ) \ + ( ( gindex ) / FTC_FAMILY( gfam )->item_count ) /* find a glyph index's chunk, and return its start index */ -#define FTC_GLYPH_FAMILY_START( gfam, gindex ) \ - ( FTC_GLYPH_FAMILY_CHUNK( gfam, gindex ) * \ - FTC_GLYPH_FAMILY( gfam )->item_count ) - - /* compute a glyph request's hash value */ -#define FTC_GLYPH_FAMILY_HASH( gfam, gindex ) \ - ( (FT_UFast)( \ - ( FTC_GLYPH_FAMILY( gfam )->hash << 16 ) | \ - ( FTC_GLYPH_FAMILY_CHUNK( gfam, gindex ) & 0xFFFFU ) ) ) - - /* must be called in an FTC_Family_CompareFunc to update the query */ - /* whenever a glyph set is matched in the lookup, or when it */ - /* is created */ -#define FTC_GLYPH_FAMILY_FOUND( gfam, gquery ) \ - do \ - { \ - FTC_QUERY( gquery )->family = FTC_FAMILY( gfam ); \ - FTC_QUERY( gquery )->hash = \ - FTC_GLYPH_FAMILY_HASH( gfam, \ - FTC_GLYPH_QUERY( gquery )->gindex ); \ - } while ( 0 ) - - /* retrieve glyph index of glyph node */ -#define FTC_GLYPH_NODE_GINDEX( x ) \ - ( (FT_UInt)( FTC_GLYPH_NODE( x )->node.hash & 0xFFFFU ) ) - +#define FTC_FAMILY_START( gfam, gindex ) \ + ( FTC_FAMILY_CHUNK( gfam, gindex ) * \ + FTC_FAMILY( gfam )->item_count ) /*************************************************************************/ /* */ @@ -149,36 +185,78 @@ FT_BEGIN_HEADER /* must be called by derived FTC_Node_InitFunc routines */ FT_EXPORT( void ) - ftc_glyph_node_init( FTC_GlyphNode node, - FT_UInt gindex, /* glyph index for node */ - FTC_GlyphFamily gfam ); + FTC_GNode_Init( FTC_GNode node, + FT_UInt gindex, /* glyph index for node */ + FTC_Family family ); /* returns TRUE iff the query's glyph index correspond to the node; */ /* this assumes that the "family" and "hash" fields of the query are */ /* already correctly set */ FT_EXPORT( FT_Bool ) - ftc_glyph_node_compare( FTC_GlyphNode gnode, - FTC_GlyphQuery gquery ); + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ); + + /* call this function to clear a node's family. this is necessary + * to implement the "node_remove_faceid" cache method correctly + */ + FT_EXPORT( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ); /* must be called by derived FTC_Node_DoneFunc routines */ FT_EXPORT( void ) - ftc_glyph_node_done( FTC_GlyphNode node, - FTC_Cache cache ); + FTC_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + typedef struct FTC_GCacheRec_ + { + FTC_CacheRec cache; + FTC_MruListRec families; + + } FTC_GCacheRec, *FTC_GCache; - /* must be called by derived FTC_Family_InitFunc; */ - /* calls "ftc_family_init" */ +#define FTC_GCACHE(x) ((FTC_GCache)(x)) + + + /* can be used as @FTC_Cache_InitFunc */ FT_EXPORT( FT_Error ) - ftc_glyph_family_init( FTC_GlyphFamily gfam, - FT_UInt32 hash, - FT_UInt item_count, - FT_UInt item_total, - FTC_GlyphQuery gquery, - FTC_Cache cache ); + FTC_GCache_Init( FTC_GCache cache ); + + /* can be used as @FTC_Cache_DoneFunc */ FT_EXPORT( void ) - ftc_glyph_family_done( FTC_GlyphFamily gfam ); + FTC_GCache_Done( FTC_GCache cache ); + + + /* the glyph cache class adds fields for the family implementation */ + typedef struct FTC_GCacheClassRec_ + { + FTC_CacheClassRec clazz; + FTC_MruListClass family_class; + + } FTC_GCacheClassRec; + typedef const FTC_GCacheClassRec* FTC_GCacheClass; + +#define FTC_GCACHE_CLASS(x) ((FTC_GCacheClass)(x)) + +#define FTC_CACHE__GCACHE_CLASS(x) FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class ) + + + /* convenience function. use instead of FTC_Manager_Register_Cache */ + FT_EXPORT( FT_Error ) + FTC_GCache_New( FTC_Manager manager, + FTC_GCacheClass clazz, + FTC_GCache *acache ); + + FT_EXPORT( FT_Error ) + FTC_GCache_Lookup( FTC_GCache cache, + FT_UInt32 hash, + FT_UInt gindex, + FTC_GQuery query, + FTC_Node *anode ); /* */ diff --git a/include/freetype/cache/ftcimage.h b/include/freetype/cache/ftcimage.h index 2d0b780e1..69ed9e51d 100644 --- a/include/freetype/cache/ftcimage.h +++ b/include/freetype/cache/ftcimage.h @@ -2,7 +2,7 @@ /* */ /* ftcimage.h */ /* */ -/* FreeType Image cache (specification). */ +/* FreeType Generic Image cache (specification) */ /* */ /* Copyright 2000-2001, 2002, 2003 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ @@ -16,6 +16,15 @@ /***************************************************************************/ + /* + * FTC_ICache is an _abstract_ cache used to store a single FT_Glyph + * image per cache node. + * + * FTC_ICache extends FTC_GCache. For an implementation example, + * see FTC_ImageCache in "src/cache/ftbasic.c" + * + */ + /*************************************************************************/ /* */ /* Each image cache really manages FT_Glyph objects. */ @@ -29,284 +38,64 @@ #include #include FT_CACHE_H - +#include FT_CACHE_INTERNAL_GLYPH_H FT_BEGIN_HEADER - /*************************************************************************/ - /* */ - /*
*/ - /* cache_subsystem */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** IMAGE CACHE OBJECT *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - - /************************************************************************** - * - * @struct: - * FTC_ImageTypeRec - * - * @description: - * A simple structure used to describe the type of glyph image to be - * loaded into the cache. - * - * @fields: - * font :: An @FTC_FontRec used to describe the glyph's face and size. - * - * flags :: The load flags to be applied when loading the glyph; see - * the @FT_LOAD_XXX constants for details. - * - * @note: - * This type completely replaces the @FTC_Image_Desc structure which is - * now obsolete. - */ - typedef struct FTC_ImageTypeRec_ + /* the FT_Glyph image node type - we store only 1 glyph per node */ + typedef struct FTC_INodeRec_ { - FTC_FontRec font; - FT_Int32 flags; + FTC_GNodeRec gnode; + FT_Glyph glyph; - } FTC_ImageTypeRec; - - typedef struct FTC_ImageTypeRec_* FTC_ImageType; - - /* */ + } FTC_INodeRec, *FTC_INode; -#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ - ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) && \ - (d1)->flags == (d2)->flags ) +#define FTC_INODE( x ) ( (FTC_INode)( x ) ) +#define FTC_INODE_GINDEX( x ) FTC_GNODE(x)->gindex +#define FTC_INODE_FAMILY( x ) FTC_GNODE(x)->family -#define FTC_IMAGE_TYPE_HASH( d ) \ - (FT_UFast)( FTC_FONT_HASH( &(d)->font ) ^ \ - ( (d)->flags << 4 ) ) + typedef FT_Error (*FTC_IFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Cache cache, + FT_Glyph *aglyph ); - - /*************************************************************************/ - /* */ - /* */ - /* FTC_ImageCache */ - /* */ - /* */ - /* A handle to an glyph image cache object. They are designed to */ - /* hold many distinct glyph images while not exceeding a certain */ - /* memory threshold. */ - /* */ - typedef struct FTC_ImageCacheRec_* FTC_ImageCache; - - - /*************************************************************************/ - /* */ - /* */ - /* FTC_ImageCache_New */ - /* */ - /* */ - /* Creates a new glyph image cache. */ - /* */ - /* */ - /* manager :: The parent manager for the image cache. */ - /* */ - /* */ - /* acache :: A handle to the new glyph image cache object. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - FT_EXPORT( FT_Error ) - FTC_ImageCache_New( FTC_Manager manager, - FTC_ImageCache *acache ); - - - /*************************************************************************/ - /* */ - /* */ - /* FTC_ImageCache_Lookup */ - /* */ - /* */ - /* Retrieves a given glyph image from a glyph image cache. */ - /* */ - /* */ - /* cache :: A handle to the source glyph image cache. */ - /* */ - /* type :: A pointer to a glyph image type descriptor. */ - /* */ - /* gindex :: The glyph index to retrieve. */ - /* */ - /* */ - /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ - /* failure. */ - /* */ - /* anode :: Used to return the address of of the corresponding cache */ - /* node after incrementing its reference count (see note */ - /* below). */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* The returned glyph is owned and managed by the glyph image cache. */ - /* Never try to transform or discard it manually! You can however */ - /* create a copy with @FT_Glyph_Copy and modify the new one. */ - /* */ - /* If "anode" is _not_ NULL, it receives the address of the cache */ - /* node containing the glyph image, after increasing its reference */ - /* count. This ensures that the node (as well as the FT_Glyph) will */ - /* always be kept in the cache until you call @FTC_Node_Unref to */ - /* "release" it. */ - /* */ - /* If "anode" is NULL, the cache node is left unchanged, which means */ - /* that the FT_Glyph could be flushed out of the cache on the next */ - /* call to one of the caching sub-system APIs. Don't assume that it */ - /* is persistent! */ - /* */ - FT_EXPORT( FT_Error ) - FTC_ImageCache_Lookup( FTC_ImageCache cache, - FTC_ImageType type, - FT_UInt gindex, - FT_Glyph *aglyph, - FTC_Node *anode ); - - /* */ - -#define ftc_image_format( x ) ( (x) & 7 ) - - -#define ftc_image_format_bitmap 0x0000 -#define ftc_image_format_outline 0x0001 - -#define ftc_image_format_mask 0x000F - -#define ftc_image_flag_monochrome 0x0010 -#define ftc_image_flag_unhinted 0x0020 -#define ftc_image_flag_autohinted 0x0040 -#define ftc_image_flag_unscaled 0x0080 -#define ftc_image_flag_no_sbits 0x0100 - - /* monochrome bitmap */ -#define ftc_image_mono ftc_image_format_bitmap | \ - ftc_image_flag_monochrome - - /* anti-aliased bitmap */ -#define ftc_image_grays ftc_image_format_bitmap - - /* scaled outline */ -#define ftc_image_outline ftc_image_format_outline - - - /*************************************************************************/ - /* */ - /* */ - /* FTC_Image_Desc */ - /* */ - /* */ - /* THIS TYPE IS DEPRECATED. Use @FTC_ImageTypeRec instead. */ - /* */ - /* A simple structure used to describe a given glyph image category. */ - /* */ - /* */ - /* font :: An @FTC_FontRec used to describe the glyph's face */ - /* and size. */ - /* */ - /* image_type :: The glyph image's type. */ - /* */ - typedef struct FTC_Image_Desc_ + typedef struct FTC_IFamilyClassRec_ { - FTC_FontRec font; - FT_UInt image_type; + FTC_MruListClassRec clazz; + FTC_IFamily_LoadGlyphFunc family_load_glyph; - } FTC_Image_Desc; + } FTC_IFamilyClassRec; + typedef const FTC_IFamilyClassRec* FTC_IFamilyClass; - /*************************************************************************/ - /* */ - /* */ - /* FTC_Image_Cache */ - /* */ - /* */ - /* THIS TYPE IS DEPRECATED. Use @FTC_ImageCache instead. */ - /* */ - typedef FTC_ImageCache FTC_Image_Cache; - +#define FTC_IFAMILY_CLASS(x) ((FTC_IFamilyClass)(x)) - /*************************************************************************/ - /* */ - /* */ - /* FTC_Image_Cache_New */ - /* */ - /* */ - /* THIS FUNCTION IS DEPRECATED. Use @FTC_ImageCache_New instead. */ - /* */ - /* Creates a new glyph image cache. */ - /* */ - /* */ - /* manager :: The parent manager for the image cache. */ - /* */ - /* */ - /* acache :: A handle to the new glyph image cache object. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - FT_EXPORT( FT_Error ) - FTC_Image_Cache_New( FTC_Manager manager, - FTC_Image_Cache *acache ); +#define FTC_CACHE__IFAMILY_CLASS(x) \ + FTC_IFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class ) + /* can be used as a @FTC_Node_FreeFunc */ + FT_EXPORT( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_Image_Cache_Lookup */ - /* */ - /* */ - /* THIS FUNCTION IS DEPRECATED. Use @FTC_ImageCache_Lookup instead. */ - /* */ - /* */ - /* cache :: A handle to the source glyph image cache. */ - /* */ - /* desc :: A pointer to a glyph image descriptor. */ - /* */ - /* gindex :: The glyph index to retrieve. */ - /* */ - /* */ - /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ - /* failure. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* The returned glyph is owned and managed by the glyph image cache. */ - /* Never try to transform or discard it manually! You can however */ - /* create a copy with @FT_Glyph_Copy and modify the new one. */ - /* */ - /* Because the glyph image cache limits the total amount of memory */ - /* taken by the glyphs it holds, the returned glyph might disappear */ - /* on a later invocation of this function! It is a cache after */ - /* all... */ - /* */ - /* Use this function to "lock" the glyph as long as it is needed. */ - /* */ + /* can be used as @FTC_Node_NewFunc. "gquery.index" & "gquery.family" must + * be set correctly. this function will call the 'family_load_glyph' method + * to load the FT_Glyph into the cache node + */ FT_EXPORT( FT_Error ) - FTC_Image_Cache_Lookup( FTC_Image_Cache cache, - FTC_Image_Desc* desc, - FT_UInt gindex, - FT_Glyph *aglyph ); + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ); + + /* can be used as @FTC_Node_WeightFunc */ + FT_EXPORT( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ); /* */ FT_END_HEADER - #endif /* __FTCIMAGE_H__ */ diff --git a/include/freetype/cache/ftcmanag.h b/include/freetype/cache/ftcmanag.h index 97c77591b..34f3857e4 100644 --- a/include/freetype/cache/ftcmanag.h +++ b/include/freetype/cache/ftcmanag.h @@ -65,7 +65,7 @@ #include #include FT_CACHE_H -#include FT_CACHE_INTERNAL_LRU_H +#include FT_CACHE_INTERNAL_MRU_H #include FT_CACHE_INTERNAL_CACHE_H @@ -80,99 +80,32 @@ FT_BEGIN_HEADER /*************************************************************************/ -#define FTC_MAX_FACES_DEFAULT 2 -#define FTC_MAX_SIZES_DEFAULT 4 -#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */ +#define FTC_MAX_FACES_DEFAULT 2 +#define FTC_MAX_SIZES_DEFAULT 4 +#define FTC_MAX_BYTES_DEFAULT 200000L /* ~200kByte by default */ /* maximum number of caches registered in a single manager */ #define FTC_MAX_CACHES 16 - - typedef struct FTC_FamilyEntryRec_ - { - FTC_Family family; - FTC_Cache cache; - FT_UInt index; - FT_UInt link; - - } FTC_FamilyEntryRec, *FTC_FamilyEntry; - - -#define FTC_FAMILY_ENTRY_NONE ( (FT_UInt)-1 ) - - - typedef struct FTC_FamilyTableRec_ - { - FT_UInt count; - FT_UInt size; - FTC_FamilyEntry entries; - FT_UInt free; - - } FTC_FamilyTableRec, *FTC_FamilyTable; - - - FT_EXPORT( FT_Error ) - ftc_family_table_alloc( FTC_FamilyTable table, - FT_Memory memory, - FTC_FamilyEntry *aentry ); - - FT_EXPORT( void ) - ftc_family_table_free( FTC_FamilyTable table, - FT_UInt idx ); - - - /*************************************************************************/ - /* */ - /* */ - /* FTC_ManagerRec */ - /* */ - /* */ - /* The cache manager structure. */ - /* */ - /* */ - /* library :: A handle to a FreeType library instance. */ - /* */ - /* faces_list :: The lru list of @FT_Face objects in the cache. */ - /* */ - /* sizes_list :: The lru list of @FT_Size objects in the cache. */ - /* */ - /* max_weight :: The maximum cache pool weight. */ - /* */ - /* cur_weight :: The current cache pool weight. */ - /* */ - /* num_nodes :: The current number of nodes in the manager. */ - /* */ - /* nodes_list :: The global lru list of all cache nodes. */ - /* */ - /* caches :: A table of installed/registered cache objects. */ - /* */ - /* request_data :: User-provided data passed to the requester. */ - /* */ - /* request_face :: User-provided function used to implement a mapping */ - /* between abstract @FTC_FaceID values and real */ - /* @FT_Face objects. */ - /* */ - /* families :: Global table of families. */ - /* */ typedef struct FTC_ManagerRec_ { FT_Library library; - FT_LruList faces_list; - FT_LruList sizes_list; + FT_Memory memory; + FTC_Node nodes_list; FT_ULong max_weight; FT_ULong cur_weight; - FT_UInt num_nodes; - FTC_Node nodes_list; - FTC_Cache caches[FTC_MAX_CACHES]; + FTC_Cache caches[ FTC_MAX_CACHES ]; + FT_UInt num_caches; + + FTC_MruListRec faces; + FTC_MruListRec sizes; FT_Pointer request_data; FTC_Face_Requester request_face; - FTC_FamilyTableRec families; - } FTC_ManagerRec; @@ -201,43 +134,58 @@ FT_BEGIN_HEADER FTC_Manager_Compress( FTC_Manager manager ); + /* try to flush "count" old nodes from the cache. return the number + * of really flushed nodes + */ + FT_EXPORT( FT_UInt ) + FTC_Manager_FlushN( FTC_Manager manager, + FT_UInt count ); + + /* this must be used internally for the moment */ FT_EXPORT( FT_Error ) - FTC_Manager_Register_Cache( FTC_Manager manager, - FTC_Cache_Class clazz, - FTC_Cache *acache ); + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, + FTC_Cache *acache ); + /* */ - /* can be called to increment a node's reference count */ - FT_EXPORT( void ) - FTC_Node_Ref( FTC_Node node, - FTC_Manager manager ); + typedef struct FTC_ScalerRec_ + { + FTC_FaceID face_id; + FT_UInt width; + FT_UInt height; + FT_Int pixel; + FT_UInt x_res; + FT_UInt y_res; + + } FTC_ScalerRec, *FTC_Scaler; - /*************************************************************************/ - /* */ - /* */ - /* FTC_Node_Unref */ - /* */ - /* */ - /* Decrement a cache node's internal reference count. When the count */ - /* reaches 0, it is not destroyed but becomes eligible for subsequent */ - /* cache flushes. */ - /* */ - /* */ - /* node :: The cache node handle. */ - /* */ - /* manager :: The cache manager handle. */ - /* */ - FT_EXPORT( void ) - FTC_Node_Unref( FTC_Node node, - FTC_Manager manager ); +#define FTC_SCALER_COMPARE(a,b) \ + ( (a)->face_id == (b)->face_id && \ + (a)->width == (b)->width && \ + (a)->height == (b)->height && \ + ((a)->pixel != 0) == ((b)->pixel != 0) && \ + ( (a)->pixel || \ + ( (a)->x_res == (b)->x_res && \ + (a)->y_res == (b)->y_res ) ) ) + +#define FTC_SCALER_HASH(q) \ + ( FTC_FACE_ID_HASH((q)->face_id) + \ + (q)->width + (q)->height*7 + \ + (q)->pixel ? ( (q)->x_res*33 ^ (q)->y_res*61 ) : 0 ) + + + FT_EXPORT( FT_Error ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ); /* */ FT_END_HEADER - #endif /* __FTCMANAG_H__ */ diff --git a/include/freetype/cache/ftcmru.h b/include/freetype/cache/ftcmru.h new file mode 100644 index 000000000..e0232fbff --- /dev/null +++ b/include/freetype/cache/ftcmru.h @@ -0,0 +1,143 @@ +/***************************************************************************/ +/* */ +/* ftcmru.h */ +/* */ +/* Simple MRU list-cache (specification). */ +/* */ +/* Copyright 2000-2001, 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. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* An MRU is a list that cannot hold more than a certain number of */ + /* elements (`max_elements'). All elements in the list are sorted in */ + /* least-recently-used order, i.e., the `oldest' element is at the tail */ + /* of the list. */ + /* */ + /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ + /* the list is searched for an element with the corresponding key. If */ + /* it is found, the element is moved to the head of the list and is */ + /* returned. */ + /* */ + /* If no corresponding element is found, the lookup routine will try to */ + /* obtain a new element with the relevant key. If the list is already */ + /* full, the oldest element from the list is discarded and replaced by a */ + /* new one; a new element is added to the list otherwise. */ + /* */ + /* Note that it is possible to pre-allocate the element list nodes. */ + /* This is handy if `max_elements' is sufficiently small, as it saves */ + /* allocations/releases during the lookup process. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCMRU_H__ +#define __FTCMRU_H__ + + +#include +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + + } FTC_MruNodeRec; + + typedef FT_Int (*FTC_MruNode_CompareFunc)( FTC_MruNode node, + FT_Pointer key ); + + typedef FT_Error (*FTC_MruNode_InitFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef FT_Error (*FTC_MruNode_ResetFunc)( FTC_MruNode node, + FT_Pointer key, + FT_Pointer data ); + + typedef void (*FTC_MruNode_DoneFunc)( FTC_MruNode node, + FT_Pointer data ); + + typedef struct FTC_MruListClassRec_ + { + FT_UInt node_size; + FTC_MruNode_CompareFunc node_compare; + FTC_MruNode_InitFunc node_init; + FTC_MruNode_ResetFunc node_reset; + FTC_MruNode_DoneFunc node_done; + + } FTC_MruListClassRec; + + typedef struct FTC_MruListRec_ + { + FT_UInt num_nodes; + FT_UInt max_nodes; + FTC_MruNode nodes; + FT_Pointer data; + FTC_MruListClassRec clazz; + FT_Memory memory; + + } FTC_MruListRec; + + + FT_EXPORT( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ); + + FT_EXPORT( void ) + FTC_MruList_Reset( FTC_MruList list ); + + + FT_EXPORT( void ) + FTC_MruList_Done( FTC_MruList list ); + + + FT_EXPORT( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *pnode ); + + FT_EXPORT( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ); + + FT_EXPORT( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc select, + FT_Pointer key ); + /* */ + +FT_END_HEADER + + +#endif /* __FTCMRU_H__ */ + + +/* END */ diff --git a/include/freetype/cache/ftcsbits.h b/include/freetype/cache/ftcsbits.h index 6f8ef99cf..e79543a6a 100644 --- a/include/freetype/cache/ftcsbits.h +++ b/include/freetype/cache/ftcsbits.h @@ -22,251 +22,69 @@ #include #include FT_CACHE_H -#include FT_CACHE_IMAGE_H +#include FT_CACHE_INTERNAL_GLYPH_H FT_BEGIN_HEADER +#define FTC_SBIT_ITEMS_PER_NODE 16 - /*************************************************************************/ - /* */ - /*
*/ - /* cache_subsystem */ - /* */ - /*************************************************************************/ - + typedef struct FTC_SNodeRec_ + { + FTC_GNodeRec gnode; + FT_UInt count; + FTC_SBitRec sbits[ FTC_SBIT_ITEMS_PER_NODE ]; - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBit */ - /* */ - /* */ - /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */ - /* structure for details. */ - /* */ - typedef struct FTC_SBitRec_* FTC_SBit; + } FTC_SNodeRec, *FTC_SNode; - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBitRec */ - /* */ - /* */ - /* A very compact structure used to describe a small glyph bitmap. */ - /* */ - /* */ - /* width :: The bitmap width in pixels. */ - /* */ - /* height :: The bitmap height in pixels. */ - /* */ - /* left :: The horizontal distance from the pen position to the */ - /* left bitmap border (a.k.a. `left side bearing', or */ - /* `lsb'). */ - /* */ - /* top :: The vertical distance from the pen position (on the */ - /* baseline) to the upper bitmap border (a.k.a. `top */ - /* side bearing'). The distance is positive for upwards */ - /* Y coordinates. */ - /* */ - /* format :: The format of the glyph bitmap (monochrome or gray). */ - /* */ - /* max_grays :: Maximum gray level value (in the range 1 to 255). */ - /* */ - /* pitch :: The number of bytes per bitmap line. May be positive */ - /* or negative. */ - /* */ - /* xadvance :: The horizontal advance width in pixels. */ - /* */ - /* yadvance :: The vertical advance height in pixels. */ - /* */ - /* buffer :: A pointer to the bitmap pixels. */ - /* */ - typedef struct FTC_SBitRec_ - { - FT_Byte width; - FT_Byte height; - FT_Char left; - FT_Char top; +#define FTC_SNODE( x ) ( (FTC_SNode)( x ) ) +#define FTC_SNODE_GINDEX( x ) FTC_GNODE(x)->gindex +#define FTC_SNODE_FAMILY( x ) FTC_GNODE(x)->family - FT_Byte format; - FT_Byte max_grays; - FT_Short pitch; - FT_Char xadvance; - FT_Char yadvance; + typedef FT_UInt (*FTC_SFamily_GetCountFunc)( FTC_Family family, + FTC_Manager manager ); - FT_Byte* buffer; + typedef FT_Error (*FTC_SFamily_LoadGlyphFunc)( FTC_Family family, + FT_UInt gindex, + FTC_Manager manager, + FT_Face *aface ); - } FTC_SBitRec; + typedef struct FTC_SFamilyClassRec_ + { + FTC_MruListClassRec clazz; + FTC_SFamily_GetCountFunc family_get_count; + FTC_SFamily_LoadGlyphFunc family_load_glyph; + } FTC_SFamilyClassRec; - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBitCache */ - /* */ - /* */ - /* A handle to a small bitmap cache. These are special cache objects */ - /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */ - /* much more efficient way than the traditional glyph image cache */ - /* implemented by @FTC_ImageCache. */ - /* */ - typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + typedef const FTC_SFamilyClassRec* FTC_SFamilyClass; +#define FTC_SFAMILY_CLASS(x) ((FTC_SFamilyClass)(x)) - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBit_Cache */ - /* */ - /* */ - /* DEPRECATED. Use @FTC_SBitCache instead. */ - /* */ - typedef FTC_SBitCache FTC_SBit_Cache; +#define FTC_CACHE__SFAMILY_CLASS(x) \ + FTC_SFAMILY_CLASS( FTC_CACHE__GCACHE_CLASS(x)->family_class ) + FT_EXPORT( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBitCache_New */ - /* */ - /* */ - /* Creates a new cache to store small glyph bitmaps. */ - /* */ - /* */ - /* manager :: A handle to the source cache manager. */ - /* */ - /* */ - /* acache :: A handle to the new sbit cache. NULL in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ FT_EXPORT( FT_Error ) - FTC_SBitCache_New( FTC_Manager manager, - FTC_SBitCache *acache ); + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ); + FT_EXPORT( FT_ULong ) + FTC_SNode_Weight( FTC_SNode inode ); - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBitCache_Lookup */ - /* */ - /* */ - /* Looks up a given small glyph bitmap in a given sbit cache and */ - /* "lock" it to prevent its flushing from the cache until needed */ - /* */ - /* */ - /* cache :: A handle to the source sbit cache. */ - /* */ - /* type :: A pointer to the glyph image type descriptor. */ - /* */ - /* gindex :: The glyph index. */ - /* */ - /* */ - /* sbit :: A handle to a small bitmap descriptor. */ - /* */ - /* anode :: Used to return the address of of the corresponding cache */ - /* node after incrementing its reference count (see note */ - /* below). */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* The small bitmap descriptor and its bit buffer are owned by the */ - /* cache and should never be freed by the application. They might */ - /* as well disappear from memory on the next cache lookup, so don't */ - /* treat them as persistent data. */ - /* */ - /* The descriptor's `buffer' field is set to 0 to indicate a missing */ - /* glyph bitmap. */ - /* */ - /* If "anode" is _not_ NULL, it receives the address of the cache */ - /* node containing the bitmap, after increasing its reference count. */ - /* This ensures that the node (as well as the image) will always be */ - /* kept in the cache until you call @FTC_Node_Unref to "release" it. */ - /* */ - /* If "anode" is NULL, the cache node is left unchanged, which means */ - /* that the bitmap could be flushed out of the cache on the next */ - /* call to one of the caching sub-system APIs. Don't assume that it */ - /* is persistent! */ - /* */ - FT_EXPORT( FT_Error ) - FTC_SBitCache_Lookup( FTC_SBitCache cache, - FTC_ImageType type, - FT_UInt gindex, - FTC_SBit *sbit, - FTC_Node *anode ); + FT_EXPORT( FT_Bool ) + FTC_SNode_Compare( FTC_SNode snode, + FTC_GQuery gquery, + FTC_Cache cache ); /* */ - - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBit_Cache_New */ - /* */ - /* */ - /* DEPRECATED. Use @FTC_SBitCache_New instead. */ - /* */ - /* Creates a new cache to store small glyph bitmaps. */ - /* */ - /* */ - /* manager :: A handle to the source cache manager. */ - /* */ - /* */ - /* acache :: A handle to the new sbit cache. NULL in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - FT_EXPORT( FT_Error ) - FTC_SBit_Cache_New( FTC_Manager manager, - FTC_SBit_Cache *acache ); - - - /*************************************************************************/ - /* */ - /* */ - /* FTC_SBit_Cache_Lookup */ - /* */ - /* */ - /* DEPRECATED. Use @FTC_SBitCache_Lookup instead. */ - /* */ - /* Looks up a given small glyph bitmap in a given sbit cache. */ - /* */ - /* */ - /* cache :: A handle to the source sbit cache. */ - /* */ - /* desc :: A pointer to the glyph image descriptor. */ - /* */ - /* gindex :: The glyph index. */ - /* */ - /* */ - /* sbit :: A handle to a small bitmap descriptor. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* The small bitmap descriptor and its bit buffer are owned by the */ - /* cache and should never be freed by the application. They might */ - /* as well disappear from memory on the next cache lookup, so don't */ - /* treat them as persistent data. */ - /* */ - /* The descriptor's `buffer' field is set to 0 to indicate a missing */ - /* glyph bitmap. */ - /* */ - FT_EXPORT( FT_Error ) - FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache, - FTC_Image_Desc* desc, - FT_UInt gindex, - FTC_SBit *sbit ); - - FT_END_HEADER #endif /* __FTCSBITS_H__ */ diff --git a/include/freetype/cache/ftlru.h b/include/freetype/cache/ftlru.h deleted file mode 100644 index d446c60be..000000000 --- a/include/freetype/cache/ftlru.h +++ /dev/null @@ -1,208 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftlru.h */ -/* */ -/* Simple LRU list-cache (specification). */ -/* */ -/* Copyright 2000-2001, 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. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* An LRU is a list that cannot hold more than a certain number of */ - /* elements (`max_elements'). All elements in the list are sorted in */ - /* least-recently-used order, i.e., the `oldest' element is at the tail */ - /* of the list. */ - /* */ - /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ - /* the list is searched for an element with the corresponding key. If */ - /* it is found, the element is moved to the head of the list and is */ - /* returned. */ - /* */ - /* If no corresponding element is found, the lookup routine will try to */ - /* obtain a new element with the relevant key. If the list is already */ - /* full, the oldest element from the list is discarded and replaced by a */ - /* new one; a new element is added to the list otherwise. */ - /* */ - /* Note that it is possible to pre-allocate the element list nodes. */ - /* This is handy if `max_elements' is sufficiently small, as it saves */ - /* allocations/releases during the lookup process. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /********* *********/ - /********* WARNING, THIS IS BETA CODE. *********/ - /********* *********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - -#ifndef __FTLRU_H__ -#define __FTLRU_H__ - - -#include -#include FT_FREETYPE_H - -#ifdef FREETYPE_H -#error "freetype.h of FreeType 1 has been loaded!" -#error "Please fix the directory search order for header files" -#error "so that freetype.h of FreeType 2 is found first." -#endif - - -FT_BEGIN_HEADER - - - /* generic list key type */ - typedef FT_Pointer FT_LruKey; - - /* a list list handle */ - typedef struct FT_LruListRec_* FT_LruList; - - /* a list class handle */ - typedef const struct FT_LruList_ClassRec_* FT_LruList_Class; - - /* a list node handle */ - typedef struct FT_LruNodeRec_* FT_LruNode; - - /* the list node structure */ - typedef struct FT_LruNodeRec_ - { - FT_LruNode next; - FT_LruKey key; - - } FT_LruNodeRec; - - - /* the list structure */ - typedef struct FT_LruListRec_ - { - FT_Memory memory; - FT_LruList_Class clazz; - FT_LruNode nodes; - FT_UInt max_nodes; - FT_UInt num_nodes; - FT_Pointer data; - - } FT_LruListRec; - - - /* initialize a list list */ - typedef FT_Error - (*FT_LruList_InitFunc)( FT_LruList list ); - - /* finalize a list list */ - typedef void - (*FT_LruList_DoneFunc)( FT_LruList list ); - - /* this method is used to initialize a new list element node */ - typedef FT_Error - (*FT_LruNode_InitFunc)( FT_LruNode node, - FT_LruKey key, - FT_Pointer data ); - - /* this method is used to finalize a given list element node */ - typedef void - (*FT_LruNode_DoneFunc)( FT_LruNode node, - FT_Pointer data ); - - /* If defined, this method is called when the list if full */ - /* during the lookup process -- it is used to change the contents */ - /* of a list element node instead of calling `done_element()', */ - /* then `init_element()'. Set it to 0 for default behaviour. */ - typedef FT_Error - (*FT_LruNode_FlushFunc)( FT_LruNode node, - FT_LruKey new_key, - FT_Pointer data ); - - /* If defined, this method is used to compare a list element node */ - /* with a given key during a lookup. If set to 0, the `key' */ - /* fields will be directly compared instead. */ - typedef FT_Bool - (*FT_LruNode_CompareFunc)( FT_LruNode node, - FT_LruKey key, - FT_Pointer data ); - - /* A selector is used to indicate whether a given list element node */ - /* is part of a selection for FT_LruList_Remove_Selection(). The */ - /* functrion must return true (i.e., non-null) to indicate that the */ - /* node is part of it. */ - typedef FT_Bool - (*FT_LruNode_SelectFunc)( FT_LruNode node, - FT_Pointer data, - FT_Pointer list_data ); - - /* LRU class */ - typedef struct FT_LruList_ClassRec_ - { - FT_UInt list_size; - FT_LruList_InitFunc list_init; /* optional */ - FT_LruList_DoneFunc list_done; /* optional */ - - FT_UInt node_size; - FT_LruNode_InitFunc node_init; /* MANDATORY */ - FT_LruNode_DoneFunc node_done; /* optional */ - FT_LruNode_FlushFunc node_flush; /* optional */ - FT_LruNode_CompareFunc node_compare; /* optional */ - - } FT_LruList_ClassRec; - - - /* The following functions must be exported in the case where */ - /* applications would want to write their own cache classes. */ - - FT_EXPORT( FT_Error ) - FT_LruList_New( FT_LruList_Class clazz, - FT_UInt max_elements, - FT_Pointer user_data, - FT_Memory memory, - FT_LruList *alist ); - - FT_EXPORT( void ) - FT_LruList_Reset( FT_LruList list ); - - FT_EXPORT( void ) - FT_LruList_Destroy ( FT_LruList list ); - - FT_EXPORT( FT_Error ) - FT_LruList_Lookup( FT_LruList list, - FT_LruKey key, - FT_LruNode *anode ); - - FT_EXPORT( void ) - FT_LruList_Remove( FT_LruList list, - FT_LruNode node ); - - FT_EXPORT( void ) - FT_LruList_Remove_Selection( FT_LruList list, - FT_LruNode_SelectFunc select_func, - FT_Pointer select_data ); - - /* */ - -FT_END_HEADER - - -#endif /* __FTLRU_H__ */ - - -/* END */ diff --git a/include/freetype/config/ftheader.h b/include/freetype/config/ftheader.h index 22cd62ed0..da20a3315 100644 --- a/include/freetype/config/ftheader.h +++ b/include/freetype/config/ftheader.h @@ -433,7 +433,10 @@ /* see the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need */ /* to store small glyph bitmaps, as it will use less memory. */ /* */ -#define FT_CACHE_IMAGE_H + /* this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll */ + /* have all glyph image-related cache declarations */ + /* */ +#define FT_CACHE_IMAGE_H FT_CACHE_H /*************************************************************************/ @@ -450,7 +453,10 @@ /* in @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, */ /* including scalable outlines. */ /* */ -#define FT_CACHE_SMALL_BITMAPS_H + /* this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll */ + /* have all small bitmaps-related cache declarations */ + /* */ +#define FT_CACHE_SMALL_BITMAPS_H FT_CACHE_H /*************************************************************************/ @@ -462,7 +468,10 @@ /* A macro used in #include statements to name the file containing */ /* the `charmap' API of the FreeType 2 cache sub-system. */ /* */ -#define FT_CACHE_CHARMAP_H + /* this macro is *DEPRECATED*, simply include @FT_CACHE_H and you'll */ + /* have all charmap-based cache declarations */ + /* */ +#define FT_CACHE_CHARMAP_H FT_CACHE_H /*************************************************************************/ @@ -515,9 +524,13 @@ #define FT_CACHE_MANAGER_H -#define FT_CACHE_INTERNAL_LRU_H -#define FT_CACHE_INTERNAL_GLYPH_H +#define FT_CACHE_INTERNAL_MRU_H +#define FT_CACHE_INTERNAL_MANAGER_H #define FT_CACHE_INTERNAL_CACHE_H +#define FT_CACHE_INTERNAL_GLYPH_H +#define FT_CACHE_INTERNAL_IMAGE_H +#define FT_CACHE_INTERNAL_SBITS_H + #define FT_XFREE86_H diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 3581caaa6..428234e9a 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -277,8 +277,8 @@ FT_BEGIN_HEADER /* Do not #undef these macros here since the build system might define */ /* them for certain configurations only. */ /* */ -/* #define FT_DEBUG_LEVEL_ERROR */ -/* #define FT_DEBUG_LEVEL_TRACE */ +#define FT_DEBUG_LEVEL_ERROR +#define FT_DEBUG_LEVEL_TRACE /*************************************************************************/ @@ -296,7 +296,7 @@ FT_BEGIN_HEADER /* Do not #undef this macro here since the build system might define */ /* it for certain configurations only. */ /* */ -/* #define FT_DEBUG_MEMORY */ +#define FT_DEBUG_MEMORY /*************************************************************************/ diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h index 65bd21033..10178c174 100644 --- a/include/freetype/ftcache.h +++ b/include/freetype/ftcache.h @@ -63,7 +63,7 @@ FT_BEGIN_HEADER /* FTC_Face_Requester */ /* */ /* FTC_Manager_New */ - /* FTC_Manager_Lookup_Face */ + /* FTC_Manager_LookupFace */ /* FTC_Manager_Lookup_Size */ /* */ /* FTC_Node */ @@ -257,28 +257,16 @@ FT_BEGIN_HEADER /* Creates a new cache manager. */ /* */ /* */ - /* library :: The parent FreeType library handle to use. */ + /* library :: The parent FreeType library handle to use. */ /* */ - /* max_faces :: Maximum number of faces to keep alive in manager. */ - /* Use 0 for defaults (currently 2; see the value of */ - /* FTC_MAX_FACES_DEFAULT in */ - /* `include/freetype/cache/ftcmanag.h'). */ + /* max_bytes :: Maximum number of bytes to use for cached data. */ + /* Use 0 for defaults. */ /* */ - /* max_sizes :: Maximum number of sizes to keep alive in manager. */ - /* Use 0 for defaults (currently 4; see the value of */ - /* FTC_MAX_SIZES_DEFAULT in */ - /* `include/freetype/cache/ftcmanag.h'). */ + /* requester :: An application-provided callback used to translate */ + /* face IDs into real @FT_Face objects. */ /* */ - /* max_bytes :: Maximum number of bytes to use for cached data. */ - /* Use 0 for defaults (currently 200000; see the value */ - /* of FTC_MAX_BYTES_DEFAULT in */ - /* `include/freetype/cache/ftcmanag.h'). */ - /* */ - /* requester :: An application-provided callback used to translate */ - /* face IDs into real @FT_Face objects. */ - /* */ - /* req_data :: A generic pointer that is passed to the requester */ - /* each time it is called (see @FTC_Face_Requester). */ + /* req_data :: A generic pointer that is passed to the requester */ + /* each time it is called (see @FTC_Face_Requester). */ /* */ /* */ /* amanager :: A handle to a new manager object. 0 in case of */ @@ -331,7 +319,7 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ /* */ - /* FTC_Manager_Lookup_Face */ + /* FTC_Manager_LookupFace */ /* */ /* */ /* Retrieves the @FT_Face object that corresponds to a given face ID */ @@ -361,7 +349,7 @@ FT_BEGIN_HEADER /* to transform glyphs, do it yourself after glyph loading. */ /* */ FT_EXPORT( FT_Error ) - FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_Manager_LookupFace( FTC_Manager manager, FTC_FaceID face_id, FT_Face *aface ); @@ -369,48 +357,411 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ /* */ - /* FTC_Manager_Lookup_Size */ + /* FTC_Node_Unref */ /* */ /* */ - /* Retrieves the @FT_Face and @FT_Size objects that correspond to a */ - /* given font. */ + /* Decrement a cache node's internal reference count. When the count */ + /* reaches 0, it is not destroyed but becomes eligible for subsequent */ + /* cache flushes. */ /* */ /* */ + /* node :: The cache node handle. */ + /* */ + /* manager :: The cache manager handle. */ + /* */ + FT_EXPORT( void ) + FTC_Node_Unref( FTC_Node node, + FTC_Manager manager ); + + + /* remove all nodes belonging to a given face_id */ + FT_EXPORT( void ) + FTC_Manager_RemoveFaceID( FTC_Manager manager, + FTC_FaceID face_id ); + + + /*************************************************************************/ + /* */ + /*
*/ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + /************************************************************************ + * + * @type: + * FTC_CMapCache + * + * @description: + * An opaque handle used to manager a charmap cache. This cache is + * to hold character codes -> glyph indices mappings. + */ + typedef struct FTC_CMapCacheRec_* FTC_CMapCache; + + + /*************************************************************************/ + /* */ + /* @type: */ + /* FTC_CMapDesc */ + /* */ + /* @description: */ + /* A handle to an @FTC_CMapDescRec structure used to describe a given */ + /* charmap in a charmap cache. */ + /* */ + /* Each @FTC_CMapDesc describes which charmap (of which @FTC_FaceID) */ + /* we want to use in @FTC_CMapCache_Lookup. */ + /* */ + typedef struct FTC_CMapDescRec_* FTC_CMapDesc; + + + /*************************************************************************/ + /* */ + /* @function: */ + /* FTC_CMapCache_New */ + /* */ + /* @description: */ + /* Creates a new charmap cache. */ + /* */ + /* @input: */ /* manager :: A handle to the cache manager. */ /* */ - /* font :: The font to use. */ + /* @output: */ + /* acache :: A new cache handle. NULL in case of error. */ + /* */ + /* @return: */ + /* FreeType error code. 0 means success. */ + /* */ + /* @note: */ + /* Like all other caches, this one will be destroyed with the cache */ + /* manager. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_CMapCache_New( FTC_Manager manager, + FTC_CMapCache *acache ); + + + /* retrieve the index of a given charmap + */ + FT_EXPORT( FT_UInt ) + FT_Get_CharMap_Index( FT_CharMap charmap ); + + /*************************************************************************/ + /* */ + /* @function: */ + /* FTC_CMapCache_Lookup */ + /* */ + /* @description: */ + /* Translates a character code into a glyph index, using the charmap */ + /* cache. */ + /* */ + /* @input: */ + /* cache :: A charmap cache handle. */ + /* */ + /* cmap_desc :: A charmap descriptor handle. */ + /* */ + /* char_code :: The character code (in the corresponding charmap). */ + /* */ + /* @return: */ + /* Glyph index. 0 means "no glyph". */ + /* */ + /* @note: */ + /* This function doesn't return @FTC_Node handles, since there is no */ + /* real use for them with typical uses of charmaps. */ + /* */ + FT_EXPORT( FT_UInt ) + FTC_CMapCache_Lookup( FTC_CMapCache cache, + FTC_FaceID face_id, + FT_UInt cmap_index, + FT_UInt32 char_code ); + + + /*************************************************************************/ + /* */ + /*
*/ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** IMAGE CACHE OBJECT *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct FTC_ImageTypeRec_ + { + FTC_FaceID face_id; + FT_Int width; + FT_Int height; + FT_Int32 flags; + + } FTC_ImageTypeRec; + + typedef struct FTC_ImageTypeRec_* FTC_ImageType; + + /* */ + +#define FTC_IMAGE_TYPE_COMPARE( d1, d2 ) \ + ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) && \ + (d1)->flags == (d2)->flags ) + +#define FTC_IMAGE_TYPE_HASH( d ) \ + (FT_UFast)( FTC_FONT_HASH( &(d)->font ) ^ \ + ( (d)->flags << 4 ) ) + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_ImageCache */ + /* */ + /* */ + /* A handle to an glyph image cache object. They are designed to */ + /* hold many distinct glyph images while not exceeding a certain */ + /* memory threshold. */ + /* */ + typedef struct FTC_ImageCacheRec_* FTC_ImageCache; + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_ImageCache_New */ + /* */ + /* */ + /* Creates a new glyph image cache. */ + /* */ + /* */ + /* manager :: The parent manager for the image cache. */ + /* */ + /* */ + /* acache :: A handle to the new glyph image cache object. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_New( FTC_Manager manager, + FTC_ImageCache *acache ); + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_ImageCache_Lookup */ + /* */ + /* */ + /* Retrieves a given glyph image from a glyph image cache. */ + /* */ + /* */ + /* cache :: A handle to the source glyph image cache. */ + /* */ + /* type :: A pointer to a glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index to retrieve. */ /* */ /* */ - /* aface :: A pointer to the handle of the face object. Set it to */ - /* zero if you don't need it. */ + /* aglyph :: The corresponding @FT_Glyph object. 0 in case of */ + /* failure. */ /* */ - /* asize :: A pointer to the handle of the size object. Set it to */ - /* zero if you don't need it. */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ /* */ /* */ /* FreeType error code. 0 means success. */ /* */ /* */ - /* The returned @FT_Face object is always owned by the manager. You */ - /* should never try to discard it yourself. */ + /* The returned glyph is owned and managed by the glyph image cache. */ + /* Never try to transform or discard it manually! You can however */ + /* create a copy with @FT_Glyph_Copy and modify the new one. */ /* */ - /* Never change the face's transformation matrix (i.e., never call */ - /* the @FT_Set_Transform function) on a returned face! If you need */ - /* to transform glyphs, do it yourself after glyph loading. */ + /* If "anode" is _not_ NULL, it receives the address of the cache */ + /* node containing the glyph image, after increasing its reference */ + /* count. This ensures that the node (as well as the FT_Glyph) will */ + /* always be kept in the cache until you call @FTC_Node_Unref to */ + /* "release" it. */ + /* */ + /* If "anode" is NULL, the cache node is left unchanged, which means */ + /* that the FT_Glyph could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_ImageCache_Lookup( FTC_ImageCache cache, + FTC_ImageType type, + FT_UInt gindex, + FT_Glyph *aglyph, + FTC_Node *anode ); + + /*************************************************************************/ + /* */ + /*
*/ + /* cache_subsystem */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_SBit */ /* */ - /* Similarly, the returned @FT_Size object is always owned by the */ - /* manager. You should never try to discard it, and never change its */ - /* settings with @FT_Set_Pixel_Sizes or @FT_Set_Char_Size! */ + /* */ + /* A handle to a small bitmap descriptor. See the @FTC_SBitRec */ + /* structure for details. */ /* */ - /* The returned size object is the face's current size, which means */ - /* that you can call @FT_Load_Glyph with the face if you need to. */ + typedef struct FTC_SBitRec_* FTC_SBit; + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_SBitRec */ + /* */ + /* */ + /* A very compact structure used to describe a small glyph bitmap. */ + /* */ + /* */ + /* width :: The bitmap width in pixels. */ + /* */ + /* height :: The bitmap height in pixels. */ + /* */ + /* left :: The horizontal distance from the pen position to the */ + /* left bitmap border (a.k.a. `left side bearing', or */ + /* `lsb'). */ + /* */ + /* top :: The vertical distance from the pen position (on the */ + /* baseline) to the upper bitmap border (a.k.a. `top */ + /* side bearing'). The distance is positive for upwards */ + /* Y coordinates. */ + /* */ + /* format :: The format of the glyph bitmap (monochrome or gray). */ + /* */ + /* max_grays :: Maximum gray level value (in the range 1 to 255). */ + /* */ + /* pitch :: The number of bytes per bitmap line. May be positive */ + /* or negative. */ + /* */ + /* xadvance :: The horizontal advance width in pixels. */ + /* */ + /* yadvance :: The vertical advance height in pixels. */ + /* */ + /* buffer :: A pointer to the bitmap pixels. */ + /* */ + typedef struct FTC_SBitRec_ + { + FT_Byte width; + FT_Byte height; + FT_Char left; + FT_Char top; + + FT_Byte format; + FT_Byte max_grays; + FT_Short pitch; + FT_Char xadvance; + FT_Char yadvance; + + FT_Byte* buffer; + + } FTC_SBitRec; + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_SBitCache */ + /* */ + /* */ + /* A handle to a small bitmap cache. These are special cache objects */ + /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */ + /* much more efficient way than the traditional glyph image cache */ + /* implemented by @FTC_ImageCache. */ + /* */ + typedef struct FTC_SBitCacheRec_* FTC_SBitCache; + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_SBitCache_New */ + /* */ + /* */ + /* Creates a new cache to store small glyph bitmaps. */ + /* */ + /* */ + /* manager :: A handle to the source cache manager. */ + /* */ + /* */ + /* acache :: A handle to the new sbit cache. NULL in case of error. */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ /* */ FT_EXPORT( FT_Error ) - FTC_Manager_Lookup_Size( FTC_Manager manager, - FTC_Font font, - FT_Face *aface, - FT_Size *asize ); + FTC_SBitCache_New( FTC_Manager manager, + FTC_SBitCache *acache ); + + + /*************************************************************************/ + /* */ + /* */ + /* FTC_SBitCache_Lookup */ + /* */ + /* */ + /* Looks up a given small glyph bitmap in a given sbit cache and */ + /* "lock" it to prevent its flushing from the cache until needed */ + /* */ + /* */ + /* cache :: A handle to the source sbit cache. */ + /* */ + /* type :: A pointer to the glyph image type descriptor. */ + /* */ + /* gindex :: The glyph index. */ + /* */ + /* */ + /* sbit :: A handle to a small bitmap descriptor. */ + /* */ + /* anode :: Used to return the address of of the corresponding cache */ + /* node after incrementing its reference count (see note */ + /* below). */ + /* */ + /* */ + /* FreeType error code. 0 means success. */ + /* */ + /* */ + /* The small bitmap descriptor and its bit buffer are owned by the */ + /* cache and should never be freed by the application. They might */ + /* as well disappear from memory on the next cache lookup, so don't */ + /* treat them as persistent data. */ + /* */ + /* The descriptor's `buffer' field is set to 0 to indicate a missing */ + /* glyph bitmap. */ + /* */ + /* If "anode" is _not_ NULL, it receives the address of the cache */ + /* node containing the bitmap, after increasing its reference count. */ + /* This ensures that the node (as well as the image) will always be */ + /* kept in the cache until you call @FTC_Node_Unref to "release" it. */ + /* */ + /* If "anode" is NULL, the cache node is left unchanged, which means */ + /* that the bitmap could be flushed out of the cache on the next */ + /* call to one of the caching sub-system APIs. Don't assume that it */ + /* is persistent! */ + /* */ + FT_EXPORT( FT_Error ) + FTC_SBitCache_Lookup( FTC_SBitCache cache, + FTC_ImageType type, + FT_UInt gindex, + FTC_SBit *sbit, + FTC_Node *anode ); + + /* */ FT_END_HEADER diff --git a/include/freetype/ftstroke.h b/include/freetype/ftstroke.h index a92c68d62..93c189ae0 100644 --- a/include/freetype/ftstroke.h +++ b/include/freetype/ftstroke.h @@ -95,12 +95,113 @@ FT_BEGIN_HEADER } FT_Stroker_LineCap; - /* */ +/************************************************************** + * + * @enum: FT_StrokerBorder + * + * @description: + * theses values are used to select a given stroke border + * in @FT_Stroker_GetBorderCounts and @FT_Stroker_ExportBorder + * + * @values: + * FT_STROKER_BORDER_LEFT :: + * select the left border, relative to the drawing direction + * + * FT_STROKER_BORDER_RIGHT :: + * select the right border, relative to the drawing direction + * + * @note: + * applications are generally interested in the "inside" and "outside" + * borders. However, there is no direct mapping between these and + * the "left" / "right" ones, since this really depends on the glyph's + * drawing orientation, which varies between font formats + * + * you can however use @FT_Outline_GetInsideBorder and + * @FT_Outline_GetOutsideBorder to get these. + */ + typedef enum + { + FT_STROKER_BORDER_LEFT = 0, + FT_STROKER_BORDER_RIGHT + + } FT_StrokerBorder; + + +/************************************************************** + * + * @function: FT_Outline_GetInsideBorder + * + * @description: + * retrieve the @FT_StrokerBorder value corresponding to the + * "inside" borders of a given outline + * + * @input: + * outline :: source outline handle + * + * @return: + * border index. @FT_STROKER_BORDER_LEFT for empty or invalid outlines + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ); + + +/************************************************************** + * + * @function: FT_Outline_GetOutsideBorder + * + * @description: + * retrieve the @FT_StrokerBorder value corresponding to the + * "outside" borders of a given outline + * + * @input: + * outline :: source outline handle + * + * @return: + * border index. @FT_STROKER_BORDER_LEFT for empty or invalid outlines + */ + FT_EXPORT( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ); + + +/************************************************************** + * + * @function: FT_Stroker_New + * + * @description: + * create a new stroker object + * + * @input: + * memory :: memory manager handle + * + * @output: + * new stroker object handle, NULL in case of error + * + * @return: + * error code. 0 means success + */ FT_EXPORT( FT_Error ) FT_Stroker_New( FT_Memory memory, FT_Stroker *astroker ); + +/************************************************************** + * + * @function: FT_Stroker_Set + * + * @description: + * reset a stroker object's attributes + * + * @input: + * stroker :: target stroker handle + * radius :: border radius + * line_cap :: line cap style + * line_join :: line join style + * miter_limit :: miter limit for the FT_STROKER_LINEJOIN_MITER style, + * expressed as 16.16 fixed point value. + * @note: + * the radius is expressed in the same units that the outline coordinates. + */ FT_EXPORT( void ) FT_Stroker_Set( FT_Stroker stroker, FT_Fixed radius, @@ -109,29 +210,152 @@ FT_BEGIN_HEADER FT_Fixed miter_limit ); +/************************************************************** + * + * @function: FT_Stroker_ParseOutline + * + * @description: + * a convenient function used to parse a whole outline with + * the stroker. The resulting outline(s) can be retrieved + * later by functions like @FT_Stroker_GetCounts and @FT_Stroker_Export + * + * @input: + * stroker :: target stroker handle + * outline :: source outline + * opened :: boolean. if TRUE, the outline is treated as an open path, + * instead of a closed one + * + * @return:* + * error code. 0 means success + * + * @note: + * if 'opened' is 0 (the default), the outline is treated as a closed path, + * and the stroker will generate two distinct "border" outlines + * + * if 'opened' is 1, the outline is processed as an open path, and the + * stroker will generate a single "stroke" outline + */ FT_EXPORT( FT_Error ) FT_Stroker_ParseOutline( FT_Stroker stroker, FT_Outline* outline, FT_Bool opened ); +/************************************************************** + * + * @function: FT_Stroker_BeginSubPath + * + * @description: + * start a new sub-path in the stroker + * + * @input: + * stroker :: target stroker handle + * to :: pointer to start vector + * open :: boolean. if TRUE, the sub-path is treated as an open + * one + * + * @return:* + * error code. 0 means success + * + * @note: + * this function is useful when you need to stroke a path that is + * not stored as a @FT_Outline object + */ FT_EXPORT( FT_Error ) FT_Stroker_BeginSubPath( FT_Stroker stroker, FT_Vector* to, FT_Bool open ); +/************************************************************** + * + * @function: FT_Stroker_EndSubPath + * + * @description: + * close the current sub-path in the stroker + * + * @input: + * stroker :: target stroker handle + * + * @return: + * error code. 0 means success + * + * @note: + * you should call this function after @FT_Stroker_BeginSubPath. + * if the subpath was not "opened", this function will "draw" a + * single line segment to the start position when needed. + */ FT_EXPORT( FT_Error ) FT_Stroker_EndSubPath( FT_Stroker stroker ); +/************************************************************** + * + * @function: FT_Stroker_LineTo + * + * @description: + * "draw" a single line segment in the stroker's current sub-path, + * from the last position + * + * @input: + * stroker :: target stroker handle + * to :: pointer to destination point + * + * @return: + * error code. 0 means success + * + * @note: + * you should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath + */ FT_EXPORT( FT_Error ) FT_Stroker_LineTo( FT_Stroker stroker, FT_Vector* to ); +/************************************************************** + * + * @function: FT_Stroker_ConicTo + * + * @description: + * "draw" a single quadratic bezier in the stroker's current sub-path, + * from the last position + * + * @input: + * stroker :: target stroker handle + * control :: pointer to bezier control point + * to :: pointer to destination point + * + * @return: + * error code. 0 means success + * + * @note: + * you should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath + */ FT_EXPORT( FT_Error ) FT_Stroker_ConicTo( FT_Stroker stroker, FT_Vector* control, FT_Vector* to ); +/************************************************************** + * + * @function: FT_Stroker_CubicTo + * + * @description: + * "draw" a single cubic bezier in the stroker's current sub-path, + * from the last position + * + * @input: + * stroker :: target stroker handle + * control1 :: pointer to first bezier control point + * control2 :: pointer to second bezier control point + * to :: pointer to destination point + * + * @return: + * error code. 0 means success + * + * @note: + * you should call this function between @FT_Stroker_BeginSubPath and + * @FT_Stroker_EndSubPath + */ FT_EXPORT( FT_Error ) FT_Stroker_CubicTo( FT_Stroker stroker, FT_Vector* control1, @@ -139,18 +363,166 @@ FT_BEGIN_HEADER FT_Vector* to ); +/************************************************************** + * + * @function: FT_Stroker_GetBorderCounts + * + * @description: + * call this function once you finished parsing your paths + * with the stroker. It will return the number of points and + * contours necessary to export one of the "border" or "stroke" + * outlines generated by the stroker. + * + * @input: + * stroker :: target stroker handle + * border :: border index + * + * @output: + * anum_points :: number of points + * anum_contours :: number of contours + * + * @return: + * error code. 0 means success + * + * @note: + * when an outline, or a sub-path, is "closed", the stroker generates + * two independent 'border' outlines, named 'left' and 'right' + * + * when the outline, or a sub-path, is "opened", the stroker merges + * the 'border' outlines with caps. The 'left' border receives all + * points, while the 'right' border becomes empty. + * + * use the function @FT_Stroker_GetCounts instead if you want to + * retrieve the counts associated to both borders. + */ + FT_EXPORT( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ); + +/************************************************************** + * + * @function: FT_Stroker_ExportBorder + * + * @description: + * call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: target stroker handle + * border :: border index + * outline :: target outline handle + * + * @return: + * error code. 0 means success + * + * @note: + * always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * when an outline, or a sub-path, is "closed", the stroker generates + * two independent 'border' outlines, named 'left' and 'right' + * + * when the outline, or a sub-path, is "opened", the stroker merges + * the 'border' outlines with caps. The 'left' border receives all + * points, while the 'right' border becomes empty. + * + * use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once + */ + FT_EXPORT( void ) + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, + FT_Outline* outline ); + +/************************************************************** + * + * @function: FT_Stroker_GetCounts + * + * @description: + * call this function once you finished parsing your paths + * with the stroker. It will return the number of points and + * contours necessary to export all points/borders from the stroked + * outline/path. + * + * @input: + * stroker :: target stroker handle + * + * @output: + * anum_points :: number of points + * anum_contours :: number of contours + * + * @return: + * error code. 0 means success + * + * @note: + */ FT_EXPORT( FT_Error ) FT_Stroker_GetCounts( FT_Stroker stroker, FT_UInt *anum_points, FT_UInt *anum_contours ); +/************************************************************** + * + * @function: FT_Stroker_ExportBorder + * + * @description: + * call this function after @FT_Stroker_GetBorderCounts to + * export the corresponding border to your own @FT_Outline + * structure. + * + * note that this function will append the border points and + * contours to your outline, but will not try to resize its + * arrays. + * + * @input: + * stroker :: target stroker handle + * border :: border index + * outline :: target outline handle + * + * @return: + * error code. 0 means success + * + * @note: + * always call this function after @FT_Stroker_GetBorderCounts to + * get sure that there is enough room in your @FT_Outline object to + * receive all new data. + * + * when an outline, or a sub-path, is "closed", the stroker generates + * two independent 'border' outlines, named 'left' and 'right' + * + * when the outline, or a sub-path, is "opened", the stroker merges + * the 'border' outlines with caps. The 'left' border receives all + * points, while the 'right' border becomes empty. + * + * use the function @FT_Stroker_Export instead if you want to + * retrieve all borders at once + */ FT_EXPORT( void ) FT_Stroker_Export( FT_Stroker stroker, FT_Outline* outline ); +/************************************************************** + * + * @function: FT_Stroker_Done + * + * @description: + * destroy a stroker object + * + * @input: + * stroker :: stroker handle. can be NULL + */ FT_EXPORT( void ) FT_Stroker_Done( FT_Stroker stroker ); + /* */ FT_END_HEADER diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index 9becdd516..3c1e10b5c 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -399,14 +399,14 @@ hints->x_scale = x_scale; hints->y_scale = y_scale; + hints->x_delta = x_delta; + hints->y_delta = y_delta; points = hints->points; if ( hints->num_points == 0 ) goto Exit; { - /* do one thing at a time -- it is easier to understand, and */ - /* the code is clearer */ AF_Point point; AF_Point point_limit = points + hints->num_points; diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h index 2f5f4ecf2..dda37537d 100644 --- a/src/autofit/afhints.h +++ b/src/autofit/afhints.h @@ -163,7 +163,11 @@ FT_BEGIN_HEADER FT_Memory memory; FT_Fixed x_scale; + FT_Pos x_delta; + FT_Fixed y_scale; + FT_Pos y_delta; + FT_Pos edge_distance_threshold; FT_Int max_points; diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index f748b111e..70c563aa5 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -20,10 +20,7 @@ metrics->axis[ AF_DIMENSION_HORZ ].width_count = 0; metrics->axis[ AF_DIMENSION_VERT ].width_count = 0; - /* For now, compute the standard width and height from the `o' */ - /* character. I started computing the stem width of the `i' and the */ - /* stem height of the "-", but it wasn't too good. Moreover, we now */ - /* have a single character that gives us standard width and height. */ + /* For now, compute the standard width and height from the `o' */ { FT_UInt glyph_index; AF_Dimension dim; diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 0bc9eb118..33cb46475 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -40,14 +40,14 @@ FT_BEGIN_HEADER FT_Pos org; /* original position/width in font units */ FT_Pos cur; /* current/scaled position/width in device sub-pixels */ FT_Pos fit; /* current/fitted position/width in device sub-pixels */ - + } AF_WidthRec, *AF_Width; - + AF_LOCAL( void ) af_sort_pos( FT_UInt count, FT_Pos* table ); - + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -55,11 +55,11 @@ FT_BEGIN_HEADER /***** *****/ /**************************************************************************/ /**************************************************************************/ - + /* * Angle type. The auto-fitter doesn't need a very high angular accuracy, * and this allows us to speed up some computations considerably with a - * light Cordic algorithm (see afangle.c) + * light Cordic algorithm (see afangles.c) * */ @@ -111,10 +111,10 @@ FT_BEGIN_HEADER FT_Face face; FT_OutlineRec outline; FT_UInt outline_resolution; - + FT_Int advance; FT_UInt metrics_resolution; - + AF_GlyphHints hints; } AF_OutlineRec; @@ -133,7 +133,7 @@ FT_BEGIN_HEADER * auto-hinted glyph image * */ - + typedef enum { AF_SCALER_FLAG_NO_HORIZONTAL = 1, /* disable horizontal hinting */ @@ -152,7 +152,7 @@ FT_BEGIN_HEADER FT_Pos y_delta; /* in 1/64th device pixels */ FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc.. */ FT_UInt32 flags; /* additionnal control flags, see above */ - + } AF_ScalerRec, *AF_Scaler; @@ -169,7 +169,7 @@ FT_BEGIN_HEADER * the list of know scripts. Each different script correspond to the * following information: * - * - a set of Unicode ranges to test wether the face supports the + * - a set of Unicode ranges to test weither the face supports the * script * * - a specific global analyzer that will compute global metrics @@ -189,9 +189,9 @@ FT_BEGIN_HEADER { AF_SCRIPT_LATIN = 0, /* add new scripts here. don't forget to update the list in "afglobal.c" */ - + AF_SCRIPT_MAX /* do not remove */ - + } AF_Script; @@ -207,7 +207,7 @@ FT_BEGIN_HEADER /* this function parses a FT_Face to compute global metrics for * a specific script - */ + */ typedef FT_Error (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics, FT_Face face ); @@ -230,9 +230,9 @@ FT_BEGIN_HEADER { FT_UInt32 first; FT_UInt32 last; - + } AF_Script_UniRangeRec, *AF_Script_UniRange; - + typedef struct AF_ScriptClassRec_ { diff --git a/src/base/ftstroke.c b/src/base/ftstroke.c index d6d5be321..2452a9889 100644 --- a/src/base/ftstroke.c +++ b/src/base/ftstroke.c @@ -19,10 +19,31 @@ #include #include FT_STROKER_H #include FT_TRIGONOMETRY_H +#include FT_OUTLINE_H #include FT_INTERNAL_MEMORY_H #include FT_INTERNAL_DEBUG_H + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetInsideBorder( FT_Outline* outline ) + { + FT_Orientation or = FT_Outline_Get_Orientation( outline ); + + return ( or == FT_ORIENTATION_TRUETYPE ) ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT ; + } + + + FT_EXPORT_DEF( FT_StrokerBorder ) + FT_Outline_GetOutsideBorder( FT_Outline* outline ) + { + FT_Orientation or = FT_Outline_Get_Orientation( outline ); + + return ( or == FT_ORIENTATION_TRUETYPE ) ? FT_STROKER_BORDER_RIGHT + : FT_STROKER_BORDER_LEFT ; + } + + /***************************************************************************/ /***************************************************************************/ /***** *****/ @@ -221,6 +242,7 @@ FT_Bool movable; FT_Int start; /* index of current sub-path start point */ FT_Memory memory; + FT_Bool valid; } FT_StrokeBorderRec, *FT_StrokeBorder; @@ -468,6 +490,7 @@ border->num_points = 0; border->max_points = 0; border->start = -1; + border->valid = 0; } @@ -476,6 +499,7 @@ { border->num_points = 0; border->start = -1; + border->valid = 0; } @@ -491,6 +515,7 @@ border->num_points = 0; border->max_points = 0; border->start = -1; + border->valid = 0; } @@ -520,7 +545,7 @@ } else if ( in_contour == 0 ) goto Fail; - + if ( tags[0] & FT_STROKE_TAG_END ) { if ( in_contour == 0 ) @@ -534,6 +559,8 @@ if ( in_contour != 0 ) goto Fail; + border->valid = 1; + Exit: *anum_points = num_points; *anum_contours = num_contours; @@ -661,8 +688,6 @@ stroker->line_join = line_join; stroker->miter_limit = miter_limit; - stroker->valid = 0; - ft_stroke_border_reset( &stroker->borders[0] ); ft_stroke_border_reset( &stroker->borders[1] ); } @@ -1423,6 +1448,34 @@ } + FT_EXPORT_DEF( FT_Error ) + FT_Stroker_GetBorderCounts( FT_Stroker stroker, + FT_StrokerBorder border, + FT_UInt *anum_points, + FT_UInt *anum_contours ) + { + FT_UInt num_points = 0, num_contours = 0; + FT_Error error; + + if ( !stroker || border > 1 ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + error = ft_stroke_border_get_counts( stroker->borders + border, + &num_points, &num_contours ); + Exit: + if ( anum_points ) + *anum_points = num_points; + + if ( anum_contours ) + *anum_contours = num_contours; + + return error; + } + + FT_EXPORT_DEF( FT_Error ) FT_Stroker_GetCounts( FT_Stroker stroker, FT_UInt *anum_points, @@ -1446,8 +1499,6 @@ num_points = count1 + count3; num_contours = count2 + count4; - stroker->valid = 1; - Exit: *anum_points = num_points; *anum_contours = num_contours; @@ -1456,17 +1507,32 @@ FT_EXPORT_DEF( void ) - FT_Stroker_Export( FT_Stroker stroker, + FT_Stroker_ExportBorder( FT_Stroker stroker, + FT_StrokerBorder border, FT_Outline* outline ) { - if ( stroker->valid ) + if ( border == FT_STROKER_BORDER_LEFT || + border == FT_STROKER_BORDER_RIGHT ) { - ft_stroke_border_export( stroker->borders + 0, outline ); - ft_stroke_border_export( stroker->borders + 1, outline ); + FT_StrokeBorder sborder = & stroker->borders[border]; + + if ( sborder->valid ) + ft_stroke_border_export( sborder, outline ); } } + FT_EXPORT_DEF( void ) + FT_Stroker_Export( FT_Stroker stroker, + FT_Outline* outline ) + { + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); + FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); + } + + + + /* * The following is very similar to FT_Outline_Decompose, except * that we do support opened paths, and do not scale the outline. diff --git a/src/cache/Jamfile b/src/cache/Jamfile index 099fd5e36..1981bee16 100644 --- a/src/cache/Jamfile +++ b/src/cache/Jamfile @@ -14,7 +14,15 @@ HDRMACRO [ FT2_SubDir include ftcache.h ] ; if $(FT2_MULTI) { - _sources = ftlru ftcmanag ftccache ftcglyph ftcsbits ftcimage ftccmap ; + _sources = ftmru + ftcmanag + ftccache + ftcglyph + ftcsbits + ftcimage + ftcbasic + ftccmap + ; } else { diff --git a/src/cache/ftcache.c b/src/cache/ftcache.c index 07e85e1ea..4e5c07183 100644 --- a/src/cache/ftcache.c +++ b/src/cache/ftcache.c @@ -19,13 +19,13 @@ #define FT_MAKE_OPTION_SINGLE_OBJECT #include -#include "ftlru.c" +#include "ftcmru.c" #include "ftcmanag.c" #include "ftccache.c" +#include "ftccmap.c" #include "ftcglyph.c" #include "ftcimage.c" #include "ftcsbits.c" -#include "ftccmap.c" - +#include "ftcbasic.c" /* END */ diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c new file mode 100644 index 000000000..7696cbe5a --- /dev/null +++ b/src/cache/ftcbasic.c @@ -0,0 +1,380 @@ +#include +#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_Error + ftc_basic_family_reset( FTC_BasicFamily family, + FTC_BasicQuery query ) + { + family->attrs = query->attrs; + return 0; + } + + + 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; + } + + + 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; + } + + + /* + * + * 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) ftc_basic_family_reset, + (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 << 8); + + 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) ftc_basic_family_reset, + (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; + } + diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c index cc01c3978..d5d2e410b 100644 --- a/src/cache/ftccache.c +++ b/src/cache/ftccache.c @@ -17,7 +17,7 @@ #include -#include FT_CACHE_MANAGER_H +#include FT_CACHE_INTERNAL_MANAGER_H #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_DEBUG_H @@ -40,23 +40,6 @@ /*************************************************************************/ /*************************************************************************/ - FT_EXPORT_DEF( void ) - ftc_node_done( FTC_Node node, - FTC_Cache cache ) - { - FTC_Family family; - FTC_FamilyEntry entry; - - - entry = cache->manager->families.entries + node->fam_index; - family = entry->family; - - /* remove from parent set table - eventually destroy the set */ - if ( --family->num_nodes == 0 ) - FT_LruList_Remove( cache->families, (FT_LruNode) family ); - } - - /* add a new node to the head of the manager's circular MRU list */ static void ftc_node_mru_link( FTC_Node node, @@ -152,96 +135,158 @@ } + /* 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 FT_Error - ftc_node_hash_unlink( FTC_Node node, + static void + ftc_node_hash_unlink( FTC_Node node0, FTC_Cache cache ) { - FT_Error error = 0; FTC_Node *pnode; - FT_UInt idx, num_buckets; + FT_UInt idx; - idx = (FT_UInt)( node->hash & cache->mask ); + idx = (FT_UInt)( node0->hash & cache->mask ); if ( idx < cache->p ) - idx = (FT_UInt)( node->hash & ( 2 * cache->mask + 1 ) ); + idx = (FT_UInt)( node0->hash & ( 2 * cache->mask + 1 ) ); pnode = cache->buckets + idx; for (;;) { - if ( *pnode == NULL ) + FTC_Node node = *pnode; + + if ( node == NULL ) { FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" )); - return FTC_Err_Ok; + return; } - if ( *pnode == node ) - { - *pnode = node->link; - node->link = NULL; + if ( node == node0 ) break; - } pnode = &(*pnode)->link; } - num_buckets = ( cache->p + cache->mask + 1 ); - - if ( ++cache->slack > (FT_Long)num_buckets * FTC_HASH_SUB_LOAD ) - { - FT_UInt p = cache->p; - FT_UInt mask = cache->mask; - FT_UInt old_index = p + mask; - FTC_Node* pold; - - - if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) - goto Exit; - - if ( p == 0 ) - { - FT_Memory memory = cache->memory; - - - cache->mask >>= 1; - p = cache->mask; - - if ( FT_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) ) - { - FT_ERROR(( "ftc_node_hash_unlink: couldn't shunk buckets!\n" )); - goto Exit; - } - } - else - p--; - - pnode = cache->buckets + p; - while ( *pnode ) - pnode = &(*pnode)->link; - - pold = cache->buckets + old_index; - *pnode = *pold; - *pold = NULL; + *pnode = node0->link; + node0->link = NULL; - cache->slack -= FTC_HASH_MAX_LOAD; - cache->p = p; - } - - Exit: - return error; + cache->slack++; + ftc_cache_resize( cache ); } /* add a node to the "top" of its cache's hash table */ - static FT_Error + static void ftc_node_hash_link( FTC_Node node, FTC_Cache cache ) { FTC_Node *pnode; FT_UInt idx; - FT_Error error = 0; idx = (FT_UInt)( node->hash & cache->mask ); @@ -253,58 +298,8 @@ node->link = *pnode; *pnode = node; - if ( --cache->slack < 0 ) - { - FT_UInt p = cache->p; - FT_UInt mask = cache->mask; - FTC_Node new_list; - - - /* split a single bucket */ - new_list = NULL; - 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 ) - { - FT_Memory memory = cache->memory; - - - if ( FT_RENEW_ARRAY( cache->buckets, - ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) ) - { - FT_ERROR(( "ftc_node_hash_link: couldn't expand buckets!\n" )); - goto Exit; - } - - cache->mask = 2 * mask + 1; - cache->p = 0; - } - else - cache->p = p + 1; - } - - Exit: - return error; + cache->slack--; + ftc_cache_resize( cache ); } @@ -315,23 +310,19 @@ ftc_node_destroy( FTC_Node node, FTC_Manager manager ) { - FT_Memory memory = manager->library->memory; - FTC_Cache cache; - FTC_FamilyEntry entry; - FTC_Cache_Class clazz; + FTC_Cache cache; #ifdef FT_DEBUG_ERROR /* find node's cache */ - if ( node->fam_index >= manager->families.count ) + if ( node->cache_index >= manager->num_caches ) { FT_ERROR(( "ftc_node_destroy: invalid node handle\n" )); return; } #endif - entry = manager->families.entries + node->fam_index; - cache = entry->cache; + cache = manager->caches[ node->cache_index ]; #ifdef FT_DEBUG_ERROR if ( cache == NULL ) @@ -341,9 +332,7 @@ } #endif - clazz = cache->clazz; - - manager->cur_weight -= clazz->node_weight( node, cache ); + manager->cur_weight -= cache->clazz.node_weight( node, cache ); /* remove node from mru list */ ftc_node_mru_unlink( node, manager ); @@ -352,10 +341,7 @@ ftc_node_hash_unlink( node, cache ); /* now finalize it */ - if ( clazz->node_done ) - clazz->node_done( node, cache ); - - FT_FREE( node ); + cache->clazz.node_free( node, cache ); #if 0 /* check, just in case of general corruption :-) */ @@ -366,58 +352,6 @@ } - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE FAMILY DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_EXPORT_DEF( FT_Error ) - ftc_family_init( FTC_Family family, - FTC_Query query, - FTC_Cache cache ) - { - FT_Error error; - FTC_Manager manager = cache->manager; - FT_Memory memory = manager->library->memory; - FTC_FamilyEntry entry; - - - family->cache = cache; - family->num_nodes = 0; - - /* now add to manager's family table */ - error = ftc_family_table_alloc( &manager->families, memory, &entry ); - if ( !error ) - { - entry->cache = cache; - entry->family = family; - family->fam_index = entry->index; - - query->family = family; /* save family in query */ - } - - return error; - } - - - FT_EXPORT_DEF( void ) - ftc_family_done( FTC_Family family ) - { - if ( family && family->cache ) - { - FTC_Manager manager = family->cache->manager; - - - /* remove from manager's family table */ - ftc_family_table_free( &manager->families, family->fam_index ); - } - } - - /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -427,62 +361,28 @@ /*************************************************************************/ - - FT_EXPORT_DEF( FT_Error ) - ftc_cache_init( FTC_Cache cache ) + FT_EXPORT( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) { - FT_Memory memory = cache->memory; - FTC_Cache_Class clazz = cache->clazz; - FT_Error error; - + 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; + cache->p = 0; + cache->mask = FTC_HASH_INITIAL_SIZE - 1; + cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD; - if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) ) - goto Exit; - - /* now, initialize the lru list of families for this cache */ - if ( clazz->family_size > 0 ) - { - FT_LruList_ClassRec* lru_class = &cache->family_class; - - - lru_class->list_size = sizeof( FT_LruListRec ); - lru_class->list_init = NULL; - lru_class->list_done = NULL; - - lru_class->node_size = clazz->family_size; - lru_class->node_init = (FT_LruNode_InitFunc) clazz->family_init; - lru_class->node_done = (FT_LruNode_DoneFunc) clazz->family_done; - lru_class->node_flush = (FT_LruNode_FlushFunc) NULL; - lru_class->node_compare = (FT_LruNode_CompareFunc)clazz->family_compare; - - error = FT_LruList_New( (FT_LruList_Class) lru_class, - 0, /* max items == 0 => unbounded list */ - cache, - memory, - &cache->families ); - if ( error ) - FT_FREE( cache->buckets ); - } - - Exit: - return error; + return ( FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) ); } + FT_EXPORT_DEF( void ) - ftc_cache_clear( FTC_Cache cache ) + FTC_Cache_Clear( FTC_Cache cache ) { if ( cache ) { - FT_Memory memory = cache->memory; - FTC_Cache_Class clazz = cache->clazz; - FTC_Manager manager = cache->manager; - FT_UFast i; - FT_UInt count; + FTC_Manager manager = cache->manager; + FT_UFast i; + FT_UInt count; count = cache->p + cache->mask + 1; @@ -500,310 +400,228 @@ ftc_node_mru_unlink( node, manager ); /* now finalize it */ - manager->cur_weight -= clazz->node_weight( node, cache ); + manager->cur_weight -= cache->clazz.node_weight( node, cache ); - if ( clazz->node_done ) - clazz->node_done( node, cache ); - - FT_FREE( node ); + cache->clazz.node_free( node, cache ); node = next; } cache->buckets[i] = NULL; } - - cache->p = 0; - - /* destroy the families */ - if ( cache->families ) - FT_LruList_Reset( cache->families ); + ftc_cache_resize( cache ); } } - FT_EXPORT_DEF( void ) - ftc_cache_done( FTC_Cache cache ) + FT_EXPORT( void ) + FTC_Cache_Done( FTC_Cache cache ) { - if ( cache ) + if ( cache->memory ) { FT_Memory memory = cache->memory; - - ftc_cache_clear( cache ); + FTC_Cache_Clear( cache ); FT_FREE( cache->buckets ); cache->mask = 0; + cache->p = 0; cache->slack = 0; - if ( cache->families ) - { - FT_LruList_Destroy( cache->families ); - cache->families = NULL; - } + cache->memory = NULL; } } - /* Look up a node in "top" of its cache's hash table. */ - /* If not found, create a new node. */ - /* */ - FT_EXPORT_DEF( FT_Error ) - ftc_cache_lookup( FTC_Cache cache, - FTC_Query query, - FTC_Node *anode ) - { - FT_Error error = FTC_Err_Ok; - FTC_Manager manager; - FT_LruNode lru; - FT_UInt free_count = 0; - - - if ( !cache || !query || !anode ) - return FTC_Err_Invalid_Argument; - - *anode = NULL; - query->hash = 0; - query->family = NULL; - - manager = cache->manager; + static void + ftc_cache_add( FTC_Cache cache, + FT_UInt32 hash, + FTC_Node node ) + { + node->hash = hash; - /* here's a small note explaining what's happening in the code below. - * - * We need to deal intelligently with out-of-memory (OOM) conditions - * when trying to create a new family or cache node during the lookup. - * - * When an OOM is detected, we try to free one or more "old" nodes - * from the cache, then try again. It may be necessary to do that - * several times, so a loop is needed. - * - * The local variable "free_count" holds the number of "old" nodes to - * discard on each attempt. It starts at 1 and doubles on each - * iteration. The loop stops when: - * - * - a non-OOM error is detected - * - a succesful lookup is performed - * - there are no more unused nodes in the cache - * - * For the record, remember that all used nodes appear _before_ - * unused ones in the manager's MRU node list. - */ + ftc_node_hash_link( node, cache ); + ftc_node_mru_link( node, cache->manager ); - for (;;) { - { - /* first of all, find the relevant family */ - FT_LruList list = cache->families; - FT_LruNode fam, *pfam; - FT_LruNode_CompareFunc compare = list->clazz->node_compare; - - pfam = &list->nodes; - for (;;) - { - fam = *pfam; - if ( fam == NULL ) - { - error = FT_LruList_Lookup( list, query, &lru ); - if ( error ) - goto Fail; + FTC_Manager manager = cache->manager; - goto Skip; - } + manager->cur_weight += cache->clazz.node_weight( node, cache ); - if ( compare( fam, query, list->data ) ) - break; - - pfam = &fam->next; - } + if ( manager->cur_weight >= manager->max_weight ) + { + node->ref_count++; + FTC_Manager_Compress( manager ); + node->ref_count--; + } + } + } - FT_ASSERT( fam != NULL ); - /* move to top of list when needed */ - if ( fam != list->nodes ) - { - *pfam = fam->next; - fam->next = list->nodes; - list->nodes = fam; - } + 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; - lru = fam; + FTC_Node_CompareFunc compare = cache->clazz.node_compare; - Skip: - ; - } - { - FTC_Family family = (FTC_Family) lru; - FT_UFast hash = query->hash; - FTC_Node* bucket; - FT_UInt idx; + if ( cache == NULL || anode == NULL ) + return FT_Err_Invalid_Argument; + idx = hash & cache->mask; + if ( idx < cache->p ) + idx = hash & ( cache->mask * 2 + 1 ); - 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; - bucket = cache->buckets + idx; + if ( node->hash == hash && compare( node, query, cache ) ) + break; + pnode = &node->link; + } - if ( query->family != family || - family->fam_index >= manager->families.size ) - { - FT_ERROR(( - "ftc_cache_lookup: invalid query (bad 'family' field)\n" )); - error = FTC_Err_Invalid_Argument; - goto Exit; - } + if ( node != *bucket ) + { + *pnode = node->link; + node->link = *bucket; + *bucket = node; + } - if ( *bucket ) - { - FTC_Node* pnode = bucket; - FTC_Node_CompareFunc compare = cache->clazz->node_compare; + /* move to head of MRU list */ + { + FTC_Manager manager = cache->manager; + if ( node != manager->nodes_list ) + ftc_node_mru_up( node, manager ); + } + goto Exit; - for ( ;; ) - { - FTC_Node node; + 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 AddNode; - node = *pnode; - if ( node == NULL ) - break; + node = NULL; + if ( error != FT_Err_Out_Of_Memory ) + goto Exit; - if ( node->hash == hash && - (FT_UInt)node->fam_index == family->fam_index && - compare( node, query, cache ) ) - { - /* move to head of bucket list */ - if ( pnode != bucket ) - { - *pnode = node->link; - node->link = *bucket; - *bucket = node; - } + { + FTC_Manager manager = cache->manager; + FT_UInt count, tries = 1; - /* move to head of MRU list */ - if ( node != manager->nodes_list ) - ftc_node_mru_up( node, manager ); + for (;;) + { + error = cache->clazz.node_new( &node, query, cache ); + if ( !error ) + break; - *anode = node; - goto Exit; - } + node = NULL; + if ( error != FT_Err_Out_Of_Memory ) + goto Exit; - pnode = &node->link; - } - } + count = FTC_Manager_FlushN( manager, tries ); + if ( count == 0 ) + goto Exit; - /* didn't find a node, create a new one */ + if ( count == tries ) { - FTC_Cache_Class clazz = cache->clazz; - FT_Memory memory = cache->memory; - FTC_Node node; - - - if ( FT_ALLOC( node, clazz->node_size ) ) - goto Fail; - - node->fam_index = (FT_UShort) family->fam_index; - node->hash = query->hash; - node->ref_count = 0; - - error = clazz->node_init( node, query, cache ); - if ( error ) - { - FT_FREE( node ); - goto Fail; - } - - error = ftc_node_hash_link( node, cache ); - if ( error ) - { - clazz->node_done( node, cache ); - FT_FREE( node ); - goto Fail; - } - - ftc_node_mru_link( node, cache->manager ); - - cache->manager->cur_weight += clazz->node_weight( node, cache ); - - /* now try to compress the node pool when necessary */ - if ( manager->cur_weight >= manager->max_weight ) - { - node->ref_count++; - FTC_Manager_Compress( manager ); - node->ref_count--; - } - - *anode = node; + count = tries*2; + if ( count < tries || count > manager->num_nodes ) + count = manager->num_nodes; } - - /* all is well, exit now - */ - goto Exit; + tries = count; } + } - Fail: - if ( error != FTC_Err_Out_Of_Memory ) - goto Exit; - - /* There is not enough memory; try to release some unused nodes - * from the cache to make room for a new one. - */ - { - FT_UInt new_count; + 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; + } - new_count = 1 + free_count * 2; - /* check overflow and bounds */ - if ( new_count < free_count || free_count > manager->num_nodes ) - goto Exit; - free_count = new_count; - /* try to remove "new_count" nodes from the list */ - { - FTC_Node first = manager->nodes_list; - FTC_Node node; + 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; - if ( first == NULL ) /* empty list! */ - goto Exit; + for ( ;; ) + { + FTC_Node node = *pnode; - /* go to last node - it's a circular list */ - node = first->mru_prev; - for ( ; node && new_count > 0; new_count-- ) - { - FTC_Node prev = node->mru_prev; + 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; + } + } - /* Used nodes always appear before unused one in the MRU - * list. If we find one here, we'd better stop right now - * our iteration. - */ - if ( node->ref_count > 0 ) - { - /* if there are no unused nodes in the list, we'd better exit */ - if ( new_count == free_count ) - goto Exit; + /* remove all nodes in the free list + */ + while ( free ) + { + FTC_Node node; - break; - } + node = free; + free = node->link; - ftc_node_destroy( node, manager ); + manager->cur_weight -= cache->clazz.node_weight( node, cache ); + ftc_node_mru_unlink( node, manager ); - if ( node == first ) - break; + cache->clazz.node_free( node, cache ); - node = prev; - } - } - } + cache->slack ++; } - Exit: - return error; + ftc_cache_resize( cache ); } - /* END */ diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c index bdb83abb5..b107daae7 100644 --- a/src/cache/ftccmap.c +++ b/src/cache/ftccmap.c @@ -19,8 +19,7 @@ #include #include FT_FREETYPE_H #include FT_CACHE_H -#include FT_CACHE_CHARMAP_H -#include FT_CACHE_MANAGER_H +#include FT_CACHE_INTERNAL_MANAGER_H #include FT_INTERNAL_MEMORY_H #include FT_INTERNAL_DEBUG_H #include FT_TRUETYPE_IDS_H @@ -47,56 +46,41 @@ /* 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 ) ) - - - /* compute node hash value from cmap family and "requested" glyph index */ -#define FTC_CMAP_HASH( cfam, cquery ) \ - ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) ) +#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 ) - /* the charmap query */ - typedef struct FTC_CMapQueryRec_ - { - FTC_QueryRec query; - FTC_CMapDesc desc; - FT_UInt32 char_code; - - } FTC_CMapQueryRec, *FTC_CMapQuery; - - -#define FTC_CMAP_QUERY( x ) ( (FTC_CMapQuery)( x ) ) - - - /* the charmap family */ - typedef struct FTC_CMapFamilyRec_ - { - FTC_FamilyRec family; - FT_UInt32 hash; - FTC_CMapDescRec desc; - FT_UInt index; - - } FTC_CMapFamilyRec, *FTC_CMapFamily; - - -#define FTC_CMAP_FAMILY( x ) ( (FTC_CMapFamily)( x ) ) -#define FTC_CMAP_FAMILY_MEMORY( x ) FTC_FAMILY( x )->memory - - /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -108,25 +92,40 @@ /* no need for specific finalizer; we use "ftc_node_done" directly */ - /* initialize a new cmap node */ - FT_CALLBACK_DEF( FT_Error ) - ftc_cmap_node_init( FTC_CMapNode cnode, - FTC_CMapQuery cquery, + FT_CALLBACK_DEF( void ) + ftc_cmap_node_free( FTC_CMapNode node, FTC_Cache cache ) { - FT_UInt32 first; - FT_UInt n; - FT_UNUSED( cache ); + FT_Memory memory = cache->memory; + FT_FREE( node ); + } - first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) * - FTC_CMAP_INDICES_MAX; - cnode->first = first; - for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ ) - cnode->indices[n] = FTC_CMAP_UNKNOWN; + /* 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; - return 0; + 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; } @@ -142,188 +141,27 @@ /* compare a cmap node to a given query */ FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_node_compare( FTC_CMapNode cnode, - FTC_CMapQuery cquery ) - { - FT_UInt32 offset = (FT_UInt32)( cquery->char_code - cnode->first ); - - - return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CHARMAP FAMILY *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_DEF( FT_Error ) - ftc_cmap_family_init( FTC_CMapFamily cfam, - FTC_CMapQuery cquery, - FTC_Cache cache ) + ftc_cmap_node_compare( FTC_CMapNode node, + FTC_CMapQuery query ) { - FTC_Manager manager = cache->manager; - FTC_CMapDesc desc = cquery->desc; - FT_UInt32 hash = 0; - FT_Error error; - FT_Face face; - - - /* setup charmap descriptor */ - cfam->desc = *desc; - - /* let's see whether the rest is correct too */ - error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face ); - if ( !error ) + if ( node->face_id == query->face_id && + node->cmap_index == query->cmap_index ) { - FT_UInt count = face->num_charmaps; - FT_UInt idx = count; - FT_CharMap* cur = face->charmaps; - + FT_UInt32 offset = (FT_UInt32)( query->char_code - node->first ); - switch ( desc->type ) - { - case FTC_CMAP_BY_INDEX: - idx = desc->u.index; - hash = idx * 33; - break; - - case FTC_CMAP_BY_ENCODING: - if ( desc->u.encoding == FT_ENCODING_UNICODE ) - { - /* Since the `interesting' table, pid/eid (3,10), is normally the - * last one, we loop backwards. This looses with type1 fonts with - * non-BMP characters (<.0001%), this wins with .ttf with non-BMP - * chars (.01% ?), and this is the same about 99.99% of the time! - */ - - FT_UInt unicmap_idx = count; /* some UCS-2 map, if we found it */ - - - cur += count - 1; - - for ( idx = 0; idx < count; idx++, cur-- ) - { - if ( cur[0]->encoding == FT_ENCODING_UNICODE ) - { - unicmap_idx = idx; /* record we found a Unicode charmap */ - - /* XXX If some new encodings to represent UCS-4 are added, - * they should be added here. - */ - if ( ( cur[0]->platform_id == TT_PLATFORM_MICROSOFT && - cur[0]->encoding_id == TT_MS_ID_UCS_4 ) || - ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && - cur[0]->encoding_id == TT_APPLE_ID_UNICODE_32 ) ) - - /* Hurray! We found a UCS-4 charmap. We can stop the scan! */ - { - idx = count - 1 - idx; - goto Found_idx_for_FTC_CMAP_BY_ENCODING; - } - } - } - - /* We do not have any UCS-4 charmap. Sigh. - * Let's see if we have some other kind of Unicode charmap, though. - */ - if ( unicmap_idx < count ) - idx = count - 1 - unicmap_idx; - } - else - { - for ( idx = 0; idx < count; idx++, cur++ ) - if ( cur[0]->encoding == desc->u.encoding ) - break; - } - - Found_idx_for_FTC_CMAP_BY_ENCODING: - hash = idx * 67; - break; - - case FTC_CMAP_BY_ID: - for ( idx = 0; idx < count; idx++, cur++ ) - { - if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform && - (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding ) - { - hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7; - break; - } - } - break; - - default: - ; - } - - if ( idx >= count ) - goto Bad_Descriptor; - - /* compute hash value, both in family and query */ - cfam->index = idx; - cfam->hash = hash ^ FTC_FACE_ID_HASH( desc->face_id ); - FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery ); - - error = ftc_family_init( FTC_FAMILY( cfam ), - FTC_QUERY( cquery ), cache ); + return FT_BOOL( offset < FTC_CMAP_INDICES_MAX ); } - - return error; - - Bad_Descriptor: - FT_TRACE1(( "ftp_cmap_family_init: invalid charmap descriptor\n" )); - return FTC_Err_Invalid_Argument; + return 0; } FT_CALLBACK_DEF( FT_Bool ) - ftc_cmap_family_compare( FTC_CMapFamily cfam, - FTC_CMapQuery cquery ) + ftc_cmap_node_remove_faceid( FTC_CMapNode node, + FTC_FaceID face_id ) { - FT_Int result = 0; - - - /* first, compare face id and type */ - if ( cfam->desc.face_id != cquery->desc->face_id || - cfam->desc.type != cquery->desc->type ) - goto Exit; - - switch ( cfam->desc.type ) - { - case FTC_CMAP_BY_INDEX: - result = ( cfam->desc.u.index == cquery->desc->u.index ); - break; - - case FTC_CMAP_BY_ENCODING: - result = ( cfam->desc.u.encoding == cquery->desc->u.encoding ); - break; - - case FTC_CMAP_BY_ID: - result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform && - cfam->desc.u.id.encoding == cquery->desc->u.id.encoding ); - break; - - default: - ; - } - - if ( result ) - { - /* when found, update the 'family' and 'hash' field of the query */ - FTC_QUERY( cquery )->family = FTC_FAMILY( cfam ); - FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery ); - } - - Exit: - return FT_BOOL( result ); + return FT_BOOL( node->face_id == face_id ); } - /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -334,127 +172,95 @@ FT_CALLBACK_TABLE_DEF - const FTC_Cache_ClassRec ftc_cmap_cache_class = + 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_ClearFunc)ftc_cache_clear, - (FTC_Cache_DoneFunc) ftc_cache_done, - - sizeof ( FTC_CMapFamilyRec ), - (FTC_Family_InitFunc) ftc_cmap_family_init, - (FTC_Family_CompareFunc)ftc_cmap_family_compare, - (FTC_Family_DoneFunc) ftc_family_done, - - sizeof ( FTC_CMapNodeRec ), - (FTC_Node_InitFunc) ftc_cmap_node_init, - (FTC_Node_WeightFunc) ftc_cmap_node_weight, - (FTC_Node_CompareFunc)ftc_cmap_node_compare, - (FTC_Node_DoneFunc) ftc_node_done + (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_Register_Cache( - manager, - (FTC_Cache_Class)&ftc_cmap_cache_class, - FTC_CACHE_P( acache ) ); + return FTC_Manager_RegisterCache( manager, + & ftc_cmap_cache_class, + FTC_CACHE_P( acache ) ); } - - -#ifdef FTC_CACHE_USE_INLINE - -#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \ - ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) ) - -#define GEN_CACHE_NODE_COMPARE( n, q, c ) \ - ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) ) - -#define GEN_CACHE_LOOKUP ftc_cmap_cache_lookup - -#include "ftccache.i" - -#else /* !FTC_CACHE_USE_INLINE */ - -#define ftc_cmap_cache_lookup ftc_cache_lookup - -#endif /* !FTC_CACHE_USE_INLINE */ - - /* documentation is in ftccmap.h */ FT_EXPORT_DEF( FT_UInt ) - FTC_CMapCache_Lookup( FTC_CMapCache cache, - FTC_CMapDesc desc, + FTC_CMapCache_Lookup( FTC_CMapCache cmap_cache, + FTC_FaceID face_id, + FT_UInt cmap_index, FT_UInt32 char_code ) { - FTC_CMapQueryRec cquery; + 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 || !desc ) + if ( !cache ) { FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" )); return 0; } - cquery.desc = desc; - cquery.char_code = char_code; + query.face_id = face_id; + query.cmap_index = cmap_index; + query.char_code = char_code; - error = ftc_cmap_cache_lookup( FTC_CACHE( cache ), - FTC_QUERY( &cquery ), - (FTC_Node*)&node ); - if ( !error ) - { - FT_UInt offset = (FT_UInt)( char_code - node->first ); + 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( offset < FTC_CMAP_INDICES_MAX ); - - gindex = node->indices[offset]; - if ( gindex == FTC_CMAP_UNKNOWN ) - { - FT_Face face; + 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; - /* we need to use FT_Get_Char_Index */ - gindex = 0; + gindex = 0; - error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager, - desc->face_id, - &face ); - if ( !error ) - { - FT_CharMap old, cmap = NULL; - FT_UInt cmap_index; + 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; - /* save old charmap, select new one */ - old = face->charmap; - cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index; - cmap = face->charmaps[cmap_index]; + old = face->charmap; + cmap = face->charmaps[ cmap_index ]; + if (old != cmap) FT_Set_Charmap( face, cmap ); - /* perform lookup */ - gindex = FT_Get_Char_Index( face, char_code ); - node->indices[offset] = (FT_UInt16)gindex; + gindex = FT_Get_Char_Index( face, char_code ); - /* restore old charmap */ + 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 aa21228a7..f877e9b0b 100644 --- a/src/cache/ftcglyph.c +++ b/src/cache/ftcglyph.c @@ -20,7 +20,6 @@ #include FT_CACHE_H #include FT_CACHE_INTERNAL_GLYPH_H #include FT_ERRORS_H -#include FT_LIST_H #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_DEBUG_H @@ -29,45 +28,45 @@ /* create a new chunk node, setting its cache index and ref count */ FT_EXPORT_DEF( void ) - ftc_glyph_node_init( FTC_GlyphNode gnode, - FT_UInt gindex, - FTC_GlyphFamily gfam ) + FTC_GNode_Init( FTC_GNode gnode, + FT_UInt gindex, + FTC_Family family ) { - FT_UInt len; - FT_UInt start = FTC_GLYPH_FAMILY_START( gfam, gindex ); - + gnode->family = family; + gnode->gindex = gindex; + family->num_nodes++; + } - gnode->item_start = (FT_UShort)start; - len = gfam->item_total - start; - if ( len > gfam->item_count ) - len = gfam->item_count; + FT_EXPORT_DEF( void ) + FTC_GNode_UnselectFamily( FTC_GNode gnode, + FTC_Cache cache ) + { + FTC_Family family = gnode->family; - gnode->item_count = (FT_UShort)len; - gfam->family.num_nodes++; + gnode->family = NULL; + if ( family && --family->num_nodes <= 0 ) + FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family ); } FT_EXPORT_DEF( void ) - ftc_glyph_node_done( FTC_GlyphNode gnode, - FTC_Cache cache ) + FTC_GNode_Done( FTC_GNode gnode, + FTC_Cache cache ) { /* finalize the node */ - gnode->item_count = 0; - gnode->item_start = 0; + gnode->gindex = 0; - ftc_node_done( FTC_NODE( gnode ), cache ); + FTC_GNode_UnselectFamily( gnode, cache ); } FT_EXPORT_DEF( FT_Bool ) - ftc_glyph_node_compare( FTC_GlyphNode gnode, - FTC_GlyphQuery gquery ) + FTC_GNode_Compare( FTC_GNode gnode, + FTC_GQuery gquery ) { - FT_UInt start = (FT_UInt)gnode->item_start; - FT_UInt count = (FT_UInt)gnode->item_count; - - return FT_BOOL( (FT_UInt)( gquery->gindex - start ) < count ); + return FT_BOOL( gnode->family == gquery->family && + gnode->gindex == gquery->gindex ); } @@ -79,36 +78,72 @@ /*************************************************************************/ /*************************************************************************/ + 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; + } + FT_EXPORT_DEF( FT_Error ) - ftc_glyph_family_init( FTC_GlyphFamily gfam, - FT_UInt32 hash, - FT_UInt item_count, - FT_UInt item_total, - FTC_GlyphQuery gquery, - FTC_Cache cache ) + FTC_GCache_Init( FTC_GCache cache ) { - FT_Error error; - + FT_Error error; - error = ftc_family_init( FTC_FAMILY( gfam ), FTC_QUERY( gquery ), cache ); + error = FTC_Cache_Init( FTC_CACHE(cache) ); if ( !error ) { - gfam->hash = hash; - gfam->item_total = item_total; - gfam->item_count = item_count; - - FTC_GLYPH_FAMILY_FOUND( gfam, gquery ); - } + 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_glyph_family_done( FTC_GlyphFamily gfam ) + 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 ) { - ftc_family_done( FTC_FAMILY( gfam ) ); + 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; } diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c index fa1b6ac71..574ef7871 100644 --- a/src/cache/ftcimage.c +++ b/src/cache/ftcimage.c @@ -18,133 +18,60 @@ #include #include FT_CACHE_H -#include FT_CACHE_IMAGE_H -#include FT_CACHE_INTERNAL_GLYPH_H +#include FT_CACHE_INTERNAL_IMAGE_H #include FT_INTERNAL_MEMORY_H #include "ftcerror.h" - /* the FT_Glyph image node type */ - typedef struct FTC_ImageNodeRec_ - { - FTC_GlyphNodeRec gnode; - FT_Glyph glyph; - - } FTC_ImageNodeRec, *FTC_ImageNode; - - -#define FTC_IMAGE_NODE( x ) ( (FTC_ImageNode)( x ) ) -#define FTC_IMAGE_NODE_GINDEX( x ) FTC_GLYPH_NODE_GINDEX( x ) - - - /* the glyph image query */ - typedef struct FTC_ImageQueryRec_ - { - FTC_GlyphQueryRec gquery; - FTC_ImageTypeRec type; - - } FTC_ImageQueryRec, *FTC_ImageQuery; - - -#define FTC_IMAGE_QUERY( x ) ( (FTC_ImageQuery)( x ) ) - - - /* the glyph image set type */ - typedef struct FTC_ImageFamilyRec_ - { - FTC_GlyphFamilyRec gfam; - FTC_ImageTypeRec type; - - } FTC_ImageFamilyRec, *FTC_ImageFamily; - - -#define FTC_IMAGE_FAMILY( x ) ( (FTC_ImageFamily)( x ) ) -#define FTC_IMAGE_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &(x)->gfam ) - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE NODES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* finalize a given glyph image node */ - FT_CALLBACK_DEF( void ) - ftc_image_node_done( FTC_ImageNode inode, - FTC_Cache cache ) + FT_EXPORT_DEF( void ) + FTC_INode_Free( FTC_INode inode, + FTC_Cache cache ) { + FT_Memory memory = cache->memory; + if ( inode->glyph ) { FT_Done_Glyph( inode->glyph ); inode->glyph = NULL; } - ftc_glyph_node_done( FTC_GLYPH_NODE( inode ), cache ); + FTC_GNode_Done( FTC_GNODE( inode ), cache ); + FT_FREE( inode ); } /* initialize a new glyph image node */ - FT_CALLBACK_DEF( FT_Error ) - ftc_image_node_init( FTC_ImageNode inode, - FTC_GlyphQuery gquery, - FTC_Cache cache ) + FT_EXPORT_DEF( FT_Error ) + FTC_INode_New( FTC_INode *pinode, + FTC_GQuery gquery, + FTC_Cache cache ) { - FTC_ImageFamily ifam = FTC_IMAGE_FAMILY( gquery->query.family ); - FT_Error error; - FT_Face face; - FT_Size size; + FT_Memory memory = cache->memory; + FT_Error error; + FTC_INode inode; - - /* initialize its inner fields */ - ftc_glyph_node_init( FTC_GLYPH_NODE( inode ), - gquery->gindex, - FTC_GLYPH_FAMILY( ifam ) ); - - /* we will now load the glyph image */ - error = FTC_Manager_Lookup_Size( FTC_FAMILY( ifam )->cache->manager, - &ifam->type.font, - &face, &size ); - if ( !error ) + if ( !FT_NEW( inode ) ) { - FT_UInt gindex = FTC_GLYPH_NODE_GINDEX( inode ); + FTC_GNode gnode = FTC_GNODE( inode ); + FTC_Family family = gquery->family; + FT_UInt gindex = gquery->gindex; + FTC_IFamilyClass clazz = FTC_CACHE__IFAMILY_CLASS( cache ); + /* initialize its inner fields */ + FTC_GNode_Init( gnode, gindex, family ); - error = FT_Load_Glyph( face, gindex, ifam->type.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 ) - { - inode->glyph = glyph; - goto Exit; - } - } - else - error = FTC_Err_Invalid_Argument; - } + /* we will now load the glyph image */ + error = clazz->family_load_glyph( family, gindex, cache, &inode->glyph ); } - - /* in case of error */ - ftc_glyph_node_done( FTC_GLYPH_NODE(inode), cache ); - - Exit: + *pinode = inode; return error; } - FT_CALLBACK_DEF( FT_ULong ) - ftc_image_node_weight( FTC_ImageNode inode ) + FT_EXPORT_DEF( FT_ULong ) + FTC_INode_Weight( FTC_INode inode ) { FT_ULong size = 0; FT_Glyph glyph = inode->glyph; @@ -185,215 +112,4 @@ } - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE SETS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_DEF( FT_Error ) - ftc_image_family_init( FTC_ImageFamily ifam, - FTC_ImageQuery iquery, - FTC_Cache cache ) - { - FTC_Manager manager = cache->manager; - FT_Error error; - FT_Face face; - - - ifam->type = iquery->type; - - /* we need to compute "iquery.item_total" now */ - error = FTC_Manager_Lookup_Face( manager, - iquery->type.font.face_id, - &face ); - if ( !error ) - { - error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( ifam ), - FTC_IMAGE_TYPE_HASH( &ifam->type ), - 1, - face->num_glyphs, - FTC_GLYPH_QUERY( iquery ), - cache ); - } - - return error; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_image_family_compare( FTC_ImageFamily ifam, - FTC_ImageQuery iquery ) - { - FT_Bool result; - - - result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &ifam->type, &iquery->type ) ); - if ( result ) - FTC_GLYPH_FAMILY_FOUND( ifam, iquery ); - - return result; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GLYPH IMAGE CACHE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - - FT_CALLBACK_TABLE_DEF - const FTC_Cache_ClassRec ftc_image_cache_class = - { - sizeof ( FTC_CacheRec ), - (FTC_Cache_InitFunc) ftc_cache_init, - (FTC_Cache_ClearFunc)ftc_cache_clear, - (FTC_Cache_DoneFunc) ftc_cache_done, - - sizeof ( FTC_ImageFamilyRec ), - (FTC_Family_InitFunc) ftc_image_family_init, - (FTC_Family_CompareFunc)ftc_image_family_compare, - (FTC_Family_DoneFunc) ftc_glyph_family_done, - - sizeof ( FTC_ImageNodeRec ), - (FTC_Node_InitFunc) ftc_image_node_init, - (FTC_Node_WeightFunc) ftc_image_node_weight, - (FTC_Node_CompareFunc)ftc_glyph_node_compare, - (FTC_Node_DoneFunc) ftc_image_node_done - }; - - - /* documentation is in ftcimage.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_ImageCache_New( FTC_Manager manager, - FTC_ImageCache *acache ) - { - return FTC_Manager_Register_Cache( - manager, - (FTC_Cache_Class)&ftc_image_cache_class, - FTC_CACHE_P( 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_ImageQueryRec iquery; - FTC_ImageNode node; - FT_Error error; - - - /* some argument checks are delayed to ftc_cache_lookup */ - if ( !aglyph ) - return FTC_Err_Invalid_Argument; - - if ( anode ) - *anode = NULL; - - iquery.gquery.gindex = gindex; - iquery.type = *type; - - error = ftc_cache_lookup( FTC_CACHE( cache ), - FTC_QUERY( &iquery ), - (FTC_Node*)&node ); - if ( !error ) - { - *aglyph = node->glyph; - - if ( anode ) - { - *anode = (FTC_Node)node; - FTC_NODE( node )->ref_count++; - } - } - - return error; - } - - - /* backwards-compatibility functions */ - - FT_EXPORT_DEF( FT_Error ) - FTC_Image_Cache_New( FTC_Manager manager, - FTC_Image_Cache *acache ) - { - return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_Image_Cache_Lookup( FTC_Image_Cache icache, - FTC_Image_Desc* desc, - FT_UInt gindex, - FT_Glyph *aglyph ) - { - FTC_ImageTypeRec type0; - - - if ( !desc ) - return FTC_Err_Invalid_Argument; - - type0.font = desc->font; - - /* convert image type flags to load flags */ - { - FT_UInt load_flags = FT_LOAD_DEFAULT; - FT_UInt type = desc->image_type; - - - /* determine load flags, depending on the font description's */ - /* image type */ - - if ( ftc_image_format( type ) == ftc_image_format_bitmap ) - { - if ( type & ftc_image_flag_monochrome ) - load_flags |= FT_LOAD_MONOCHROME; - - /* disable embedded bitmaps loading if necessary */ - if ( type & ftc_image_flag_no_sbits ) - load_flags |= FT_LOAD_NO_BITMAP; - } - else - { - /* we want an outline, don't load embedded bitmaps */ - load_flags |= FT_LOAD_NO_BITMAP; - - if ( type & ftc_image_flag_unscaled ) - load_flags |= FT_LOAD_NO_SCALE; - } - - /* always render glyphs to bitmaps */ - load_flags |= FT_LOAD_RENDER; - - if ( type & ftc_image_flag_unhinted ) - load_flags |= FT_LOAD_NO_HINTING; - - if ( type & ftc_image_flag_autohinted ) - load_flags |= FT_LOAD_FORCE_AUTOHINT; - - type0.flags = load_flags; - } - - return FTC_ImageCache_Lookup( (FTC_ImageCache)icache, - &type0, - gindex, - aglyph, - NULL ); - } - - /* END */ diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c index 7cdb8f9da..388df2587 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -18,8 +18,7 @@ #include #include FT_CACHE_H -#include FT_CACHE_MANAGER_H -#include FT_CACHE_INTERNAL_LRU_H +#include FT_CACHE_INTERNAL_MANAGER_H #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_DEBUG_H #include FT_SIZES_H @@ -33,124 +32,135 @@ #define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data ) - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FACE LRU IMPLEMENTATION *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ + 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; - typedef struct FTC_FaceNodeRec_* FTC_FaceNode; - typedef struct FTC_SizeNodeRec_* FTC_SizeNode; + error = FTC_Manager_LookupFace( manager, scaler->face_id, &face ); + if ( error ) goto Exit; + error = FT_New_Size( face, &size ); + if ( error ) goto Exit; - typedef struct FTC_FaceNodeRec_ - { - FT_LruNodeRec lru; - FT_Face face; + FT_Activate_Size( size ); - } FTC_FaceNodeRec; + 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_ + + typedef struct FTC_SizeNodeRec_ { - FT_LruNodeRec lru; - FT_Size size; + FTC_MruNodeRec node; + FT_Size size; + FTC_ScalerRec scaler; - } FTC_SizeNodeRec; + } FTC_SizeNodeRec, *FTC_SizeNode; - FT_CALLBACK_DEF( FT_Error ) - ftc_face_node_init( FTC_FaceNode node, - FTC_FaceID face_id, - FTC_Manager manager ) + FT_CALLBACK_DEF( void ) + ftc_size_node_done( FTC_SizeNode node ) { - 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 ); - } + FT_Size size = node->size; - return error; + if ( size ) + FT_Done_Size( size ); } - /* helper function for ftc_face_node_done() */ FT_CALLBACK_DEF( FT_Bool ) - ftc_size_node_select( FTC_SizeNode node, - FT_Face face ) + ftc_size_node_compare( FTC_SizeNode node, + FTC_Scaler scaler ) { - return FT_BOOL( node->size->face == face ); + FTC_Scaler scaler0 = &node->scaler; + + return FTC_SCALER_COMPARE( scaler0, scaler ); } - FT_CALLBACK_DEF( void ) - ftc_face_node_done( FTC_FaceNode node, - FTC_Manager manager ) + + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_init( FTC_SizeNode node, + FTC_Scaler scaler, + FTC_Manager manager ) { - FT_Face face = node->face; + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); + } - /* 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 ); + FT_CALLBACK_DEF( FT_Error ) + ftc_size_node_reset( FTC_SizeNode node, + FTC_Scaler scaler, + FTC_Manager manager ) + { + FT_Done_Size( node->size ); - /* all right, we can discard the face now */ - FT_Done_Face( face ); - node->face = NULL; + node->scaler = scaler[0]; + + return ftc_scaler_lookup_size( manager, scaler, &node->size ); } - FT_CALLBACK_TABLE_DEF - const FT_LruList_ClassRec ftc_face_list_class = + static const FTC_MruListClassRec ftc_size_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 */ + 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 }; - /* documentation is in ftcache.h */ + /* 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_Lookup_Face( FTC_Manager manager, - FTC_FaceID face_id, - FT_Face *aface ) + FTC_Manager_LookupSize( FTC_Manager manager, + FTC_Scaler scaler, + FT_Size *asize ) { FT_Error error; - FTC_FaceNode node; + FTC_SizeNode node; - if ( aface == NULL ) + if ( asize == NULL ) return FTC_Err_Bad_Argument; - *aface = NULL; + *asize = NULL; if ( !manager ) return FTC_Err_Invalid_Cache_Handle; - error = FT_LruList_Lookup( manager->faces_list, - (FT_LruKey)face_id, - (FT_LruNode*)&node ); + error = FTC_MruList_Lookup( &manager->sizes, + scaler, + (FTC_MruNode*) &node ); if ( !error ) - *aface = node->face; + *asize = node->size; return error; } @@ -159,278 +169,116 @@ /*************************************************************************/ /*************************************************************************/ /***** *****/ - /***** SIZES LRU IMPLEMENTATION *****/ + /***** FACE MRU IMPLEMENTATION *****/ /***** *****/ /*************************************************************************/ /*************************************************************************/ - - typedef struct FTC_SizeQueryRec_ + typedef struct FTC_FaceNodeRec_ { - FT_Face face; - FT_UInt width; - FT_UInt height; + FTC_MruNodeRec node; + FTC_FaceID face_id; + FT_Face face; + + } FTC_FaceNodeRec, *FTC_FaceNode; - } FTC_SizeQueryRec, *FTC_SizeQuery; FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_init( FTC_SizeNode node, - FTC_SizeQuery query ) + ftc_face_node_init( FTC_FaceNode node, + FTC_FaceID face_id, + FTC_Manager manager ) { - FT_Face face = query->face; - FT_Size size; - FT_Error error; + FT_Error error; + node->face_id = face_id; - node->size = NULL; - error = FT_New_Size( face, &size ); + error = manager->request_face( face_id, + manager->library, + manager->request_data, + &node->face ); 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; + /* 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_size_node_done( FTC_SizeNode node ) + ftc_face_node_done( FTC_FaceNode node, + FTC_Manager manager ) { - if ( node->size ) - { - FT_Done_Size( node->size ); - node->size = NULL; - } - } + FT_Memory memory = manager->memory; - FT_CALLBACK_DEF( FT_Error ) - ftc_size_node_flush( FTC_SizeNode node, - FTC_SizeQuery query ) - { - FT_Size size = node->size; - FT_Error error; + /* 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; - 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_FREE( node ); } FT_CALLBACK_DEF( FT_Bool ) - ftc_size_node_compare( FTC_SizeNode node, - FTC_SizeQuery query ) + ftc_face_node_compare( FTC_FaceNode node, + FTC_FaceID face_id ) { - 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 ); + return FT_BOOL( node->face_id == face_id ); } - 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 ) + static const FTC_MruListClassRec ftc_face_list_class = { - FT_Error error; - - - /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */ - if ( aface ) - *aface = 0; + sizeof( FTC_FaceNodeRec), - 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; - } + (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 + }; - 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; - } + /* documentation is in ftcache.h */ FT_EXPORT_DEF( FT_Error ) - ftc_family_table_alloc( FTC_FamilyTable table, - FT_Memory memory, - FTC_FamilyEntry *aentry ) + FTC_Manager_LookupFace( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) { - 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; + FT_Error error; + FTC_FaceNode node; - 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; - } + if ( aface == NULL ) + return FTC_Err_Bad_Argument; - entry->link = FTC_FAMILY_ENTRY_NONE; - entry->index = idx; - } + *aface = NULL; - 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; - } + if ( !manager ) + return FTC_Err_Invalid_Cache_Handle; - entry->link = FTC_FAMILY_ENTRY_NONE; - table->count++; + error = FTC_MruList_Lookup( &manager->faces, + face_id, + (FTC_MruNode*) &node ); + if ( !error ) + *aface = node->face; - *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--; - } - } - } /*************************************************************************/ @@ -475,41 +323,28 @@ 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->memory = memory; manager->max_weight = max_bytes; - manager->cur_weight = 0; manager->request_face = requester; manager->request_data = req_data; - ftc_family_table_init( &manager->families ); + 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: - if ( error && manager ) - { - FT_LruList_Destroy( manager->faces_list ); - FT_LruList_Destroy( manager->sizes_list ); - FT_FREE( manager ); - } - return error; } @@ -526,31 +361,28 @@ if ( !manager || !manager->library ) return; - memory = manager->library->memory; + memory = manager->memory; /* now discard all caches */ - for (idx = 0; idx < FTC_MAX_CACHES; idx++ ) + for (idx = manager->num_caches; idx-- > 0; ) { FTC_Cache cache = manager->caches[idx]; - if ( cache ) { - cache->clazz->cache_done( cache ); + cache->clazz.cache_done( cache ); FT_FREE( cache ); - manager->caches[idx] = 0; + manager->caches[idx] = NULL; } } - - /* discard families table */ - ftc_family_table_done( &manager->families, memory ); + manager->num_caches = 0; /* discard faces and sizes */ - FT_LruList_Destroy( manager->faces_list ); - manager->faces_list = 0; + FTC_MruList_Done( &manager->sizes ); + FTC_MruList_Done( &manager->faces ); - FT_LruList_Destroy( manager->sizes_list ); - manager->sizes_list = 0; + manager->library = NULL; + manager->memory = NULL; FT_FREE( manager ); } @@ -563,8 +395,8 @@ { if ( manager ) { - FT_LruList_Reset( manager->sizes_list ); - FT_LruList_Reset( manager->faces_list ); + FTC_MruList_Reset( &manager->sizes ); + FTC_MruList_Reset( &manager->faces ); } /* XXX: FIXME: flush the caches? */ } @@ -576,7 +408,7 @@ FTC_Manager_Check( FTC_Manager manager ) { FTC_Node node, first; - + first = manager->nodes_list; @@ -584,23 +416,20 @@ if ( first ) { FT_ULong weight = 0; - + node = first; do { - FTC_FamilyEntry entry = manager->families.entries + node->fam_index; - FTC_Cache cache; + FTC_Cache cache = manager->caches + node->cache_index; - 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 )); + if ( (FT_UInt)node->cache_index >= manager->num_caches ) + FT_ERROR(( "FTC_Manager_Check: invalid node (cache index = %ld\n", + node->cache_index )); else { - cache = entry->cache; - weight += cache->clazz->node_weight( node, cache ); + weight += cache->clazz.node_weight( node, cache ); } node = node->mru_next; @@ -685,8 +514,8 @@ /* documentation is in ftcmanag.h */ FT_EXPORT_DEF( FT_Error ) - FTC_Manager_Register_Cache( FTC_Manager manager, - FTC_Cache_Class clazz, + FTC_Manager_RegisterCache( FTC_Manager manager, + FTC_CacheClass clazz, FTC_Cache *acache ) { FT_Error error = FTC_Err_Invalid_Argument; @@ -695,50 +524,36 @@ if ( manager && clazz && acache ) { - FT_Memory memory = manager->library->memory; - FT_UInt idx = 0; + FT_Memory memory = manager->memory; - - /* 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 ) + if ( manager->num_caches >= FTC_MAX_CACHES ) { error = FTC_Err_Too_Many_Caches; - FT_ERROR(( "FTC_Manager_Register_Cache:" )); - FT_ERROR(( " too many registered caches\n" )); + 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; + 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->cache_index = idx; + cache->index = manager->num_caches; - if ( clazz->cache_init ) + error = clazz->cache_init( cache ); + if ( error ) { - error = clazz->cache_init( cache ); - if ( error ) - { - if ( clazz->cache_done ) - clazz->cache_done( cache ); - - FT_FREE( cache ); - goto Exit; - } + clazz->cache_done( cache ); + FT_FREE( cache ); + goto Exit; } - manager->caches[idx] = cache; + manager->caches[ manager->num_caches++ ] = cache; } } @@ -748,17 +563,65 @@ } + 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 = first->mru_prev; + for ( result = 0; result < count; ) + { + FTC_Node prev = node->mru_prev; + + + /* 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->fam_index < manager->families.count && - manager->families.entries[node->fam_index].cache ) - { + if ( node && (FT_UInt)node->cache_index < manager->num_caches ) node->ref_count--; - } } diff --git a/src/cache/ftcmru.c b/src/cache/ftcmru.c new file mode 100644 index 000000000..bfc7bc55d --- /dev/null +++ b/src/cache/ftcmru.c @@ -0,0 +1,204 @@ +#include +#include FT_CACHE_H +#include FT_CACHE_INTERNAL_MRU_H +#include FT_INTERNAL_OBJECTS_H +#include FT_INTERNAL_DEBUG_H + +#include "ftcerror.h" + + FT_EXPORT_DEF( void ) + FTC_MruList_Init( FTC_MruList list, + FTC_MruListClass clazz, + FT_UInt max_nodes, + FT_Pointer data, + FT_Memory memory ) + { + list->num_nodes = 0; + list->max_nodes = max_nodes; + list->nodes = NULL; + list->clazz = *clazz; + list->data = data; + list->memory = memory; + } + + + static void + ftc_mrulist_free_nodes( FTC_MruList list, + FTC_MruNode *plist ) + { + FT_Memory memory = list->memory; + + while ( *plist ) + { + FTC_MruNode node = *plist; + + *plist = node->next; + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + } + } + + + FT_EXPORT( void ) + FTC_MruList_Reset( FTC_MruList list ) + { + ftc_mrulist_free_nodes( list, &list->nodes ); + list->num_nodes = 0; + } + + + FT_EXPORT( void ) + FTC_MruList_Done( FTC_MruList list ) + { + FTC_MruList_Reset( list ); + } + + + FT_EXPORT( FT_Error ) + FTC_MruList_Lookup( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ) + { + FT_Memory memory = list->memory; + FTC_MruNode_CompareFunc compare = list->clazz.node_compare; + FTC_MruNode *plast, *pnode, *pfirst; + FTC_MruNode node; + FT_Error error = 0; + + pfirst = &list->nodes; + plast = pnode = pfirst; + + for (;;) + { + node = *pnode; + if ( node == NULL ) + goto NewNode; + if ( compare( node, key ) ) + break; + plast = pnode; + pnode = &node->next; + } + + if ( node != *pfirst ) + { + *pnode = node->next; + node->next = *pfirst; + *pfirst = node; + } + goto Exit; + + NewNode: + if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) + { + node = *plast; + + if ( node ) + { + *plast = NULL; + list->num_nodes--; + + if ( list->clazz.node_reset ) + { + error = list->clazz.node_reset( node, key, list->data ); + if ( !error ) goto AddNode; + } + + list->clazz.node_done( node, list->data ); + } + } + else if ( FT_ALLOC( node, list->clazz.node_size ) ) + goto Exit; + + error = list->clazz.node_init( node, key, list->data ); + if ( error ) + { + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + goto Exit; + } + + AddNode: + node->next = list->nodes; + list->nodes = node; + list->num_nodes++; + + Exit: + *anode = node; + return error; + } + + + FT_EXPORT_DEF( void ) + FTC_MruList_Remove( FTC_MruList list, + FTC_MruNode node ) + { + FTC_MruNode *pnode = &list->nodes; + + for ( ;; ) + { + if ( *pnode == NULL ) /* should not happen !! */ + { + FT_ERROR(( "%s: trying to remove unknown node !!\n", + "FTC_MruList_Remove" )); + return; + } + + if ( *pnode == node ) + break; + + pnode = &node->next; + } + + *pnode = node->next; + node->next = NULL; + list->num_nodes--; + + { + FT_Memory memory = list->memory; + + if ( list->clazz.node_done ) + list->clazz.node_done( node, list->data ); + + FT_FREE( node ); + } + } + + + FT_EXPORT_DEF( void ) + FTC_MruList_RemoveSelection( FTC_MruList list, + FTC_MruNode_CompareFunc select, + FT_Pointer key ) + { + FTC_MruNode *pnode = &list->nodes; + FTC_MruNode node, free = NULL;; + + if ( select ) + { + for (;;) + { + FTC_MruNode node = *pnode; + + if ( node == NULL ) + break; + + if ( select( node, key ) ) + { + *pnode = node->next; + node->next = free; + free = node; + } + else + pnode = &node->next; + } + } + + ftc_mrulist_free_nodes( list, &free ); + } + +/* END */ + diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c index 2faf80f33..d708d3398 100644 --- a/src/cache/ftcsbits.c +++ b/src/cache/ftcsbits.c @@ -18,8 +18,7 @@ #include #include FT_CACHE_H -#include FT_CACHE_SMALL_BITMAPS_H -#include FT_CACHE_INTERNAL_GLYPH_H +#include FT_CACHE_INTERNAL_SBITS_H #include FT_INTERNAL_OBJECTS_H #include FT_INTERNAL_DEBUG_H #include FT_ERRORS_H @@ -27,47 +26,6 @@ #include "ftcerror.h" -#define FTC_SBIT_ITEMS_PER_NODE 16 - - - typedef struct FTC_SBitNodeRec_* FTC_SBitNode; - - typedef struct FTC_SBitNodeRec_ - { - FTC_GlyphNodeRec gnode; - FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE]; - - } FTC_SBitNodeRec; - - -#define FTC_SBIT_NODE( x ) ( (FTC_SBitNode)( x ) ) - - - typedef struct FTC_SBitQueryRec_ - { - FTC_GlyphQueryRec gquery; - FTC_ImageTypeRec type; - - } FTC_SBitQueryRec, *FTC_SBitQuery; - - -#define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) ) - - - typedef struct FTC_SBitFamilyRec_* FTC_SBitFamily; - - /* sbit family structure */ - typedef struct FTC_SBitFamilyRec_ - { - FTC_GlyphFamilyRec gfam; - FTC_ImageTypeRec type; - - } FTC_SBitFamilyRec; - - -#define FTC_SBIT_FAMILY( x ) ( (FTC_SBitFamily)( x ) ) -#define FTC_SBIT_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &( x )->cset ) - /*************************************************************************/ /*************************************************************************/ @@ -100,173 +58,188 @@ } - FT_CALLBACK_DEF( void ) - ftc_sbit_node_done( FTC_SBitNode snode, - FTC_Cache cache ) + FT_EXPORT_DEF( void ) + FTC_SNode_Free( FTC_SNode snode, + FTC_Cache cache ) { FTC_SBit sbit = snode->sbits; - FT_UInt count = FTC_GLYPH_NODE( snode )->item_count; + FT_UInt count = snode->count; FT_Memory memory = cache->memory; for ( ; count > 0; sbit++, count-- ) FT_FREE( sbit->buffer ); - ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache ); + FTC_GNode_Done( FTC_GNODE( snode ), cache ); + + FT_FREE( snode ); } static FT_Error - ftc_sbit_node_load( FTC_SBitNode snode, - FTC_Manager manager, - FTC_SBitFamily sfam, - FT_UInt gindex, - FT_ULong *asize ) + ftc_snode_load( FTC_SNode snode, + FTC_Manager manager, + FT_UInt gindex, + FT_ULong *asize ) { - FT_Error error; - FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); - FT_Memory memory; - FT_Face face; - FT_Size size; - FTC_SBit sbit; + FT_Error error; + FTC_GNode gnode = FTC_GNODE( snode ); + FTC_Family family = gnode->family; + FT_Memory memory = manager->memory; + FT_Face face; + FTC_SBit sbit; + FTC_SFamilyClass clazz; - if ( gindex < (FT_UInt)gnode->item_start || - gindex >= (FT_UInt)gnode->item_start + gnode->item_count ) + if ( (FT_UInt)gindex >= gnode->gindex + snode->count ) { - FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" )); + FT_ERROR(( "ftc_snode_load: invalid glyph index" )); return FTC_Err_Invalid_Argument; } - memory = manager->library->memory; + sbit = snode->sbits + ( gindex - gnode->gindex ); + clazz = (FTC_SFamilyClass) family->clazz; - sbit = snode->sbits + ( gindex - gnode->item_start ); + sbit->buffer = 0; + + error = clazz->family_load_glyph( family, gindex, manager, &face ); + if ( error ) + goto BadGlyph; - error = FTC_Manager_Lookup_Size( manager, &sfam->type.font, - &face, &size ); - if ( !error ) { - /* by default, indicates a `missing' glyph */ - sbit->buffer = 0; + FT_Int temp; + FT_GlyphSlot slot = face->glyph; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Int xadvance, yadvance; - error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER ); - if ( !error ) + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) { - FT_Int temp; - FT_GlyphSlot slot = face->glyph; - FT_Bitmap* bitmap = &slot->bitmap; - FT_Int xadvance, yadvance; - + FT_ERROR(( "%s: glyph loaded didn't returned a bitmap !!\n", + "ftc_snode_load" )); + goto BadGlyph; + } - /* check that our values fit into 8-bit containers! */ - /* If this is not the case, our bitmap is too large */ - /* and we will leave it as `missing' with sbit.buffer = 0 */ + /* check that our values fit into 8-bit containers! */ + /* If this is not the case, our bitmap is too large */ + /* and we will leave it as `missing' with sbit.buffer = 0 */ #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d ) #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d ) - /* XXX: FIXME: add support for vertical layouts maybe */ - - /* horizontal advance in pixels */ - xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6; - yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6; - - if ( CHECK_BYTE( bitmap->rows ) && - CHECK_BYTE( bitmap->width ) && - CHECK_CHAR( bitmap->pitch ) && - CHECK_CHAR( slot->bitmap_left ) && - CHECK_CHAR( slot->bitmap_top ) && - CHECK_CHAR( xadvance ) && - CHECK_CHAR( yadvance ) ) - { - sbit->width = (FT_Byte)bitmap->width; - sbit->height = (FT_Byte)bitmap->rows; - sbit->pitch = (FT_Char)bitmap->pitch; - sbit->left = (FT_Char)slot->bitmap_left; - sbit->top = (FT_Char)slot->bitmap_top; - sbit->xadvance = (FT_Char)xadvance; - sbit->yadvance = (FT_Char)yadvance; - sbit->format = (FT_Byte)bitmap->pixel_mode; - sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); - -#if 0 /* this doesn't work well with embedded bitmaps */ - - /* grab the bitmap when possible - this is a hack! */ - if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) - { - slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; - sbit->buffer = bitmap->buffer; - } - else -#endif - { - /* copy the bitmap into a new buffer -- ignore error */ - error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); - } - - /* now, compute size */ - if ( asize ) - *asize = ABS( sbit->pitch ) * sbit->height; - - } /* glyph dimensions ok */ - - } /* glyph loading successful */ - - /* ignore the errors that might have occurred -- */ - /* we mark unloaded glyphs with `sbit.buffer == 0' */ - /* and 'width == 255', 'height == 0' */ - /* */ - if ( error && error != FTC_Err_Out_Of_Memory ) - { - sbit->width = 255; - error = 0; - /* sbit->buffer == NULL too! */ - } + /* horizontal advance in pixels */ + xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6; + yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6; + + if ( !CHECK_BYTE( bitmap->rows ) || + !CHECK_BYTE( bitmap->width ) || + !CHECK_CHAR( bitmap->pitch ) || + !CHECK_CHAR( slot->bitmap_left ) || + !CHECK_CHAR( slot->bitmap_top ) || + !CHECK_CHAR( xadvance ) || + !CHECK_CHAR( yadvance ) ) + goto BadGlyph; + + sbit->width = (FT_Byte)bitmap->width; + sbit->height = (FT_Byte)bitmap->rows; + sbit->pitch = (FT_Char)bitmap->pitch; + sbit->left = (FT_Char)slot->bitmap_left; + sbit->top = (FT_Char)slot->bitmap_top; + sbit->xadvance = (FT_Char)xadvance; + sbit->yadvance = (FT_Char)yadvance; + sbit->format = (FT_Byte)bitmap->pixel_mode; + sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); + + /* copy the bitmap into a new buffer -- ignore error */ + error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); + + /* now, compute size */ + if ( asize ) + *asize = ABS( sbit->pitch ) * sbit->height; + + } /* glyph loading successful */ + + /* ignore the errors that might have occurred -- */ + /* we mark unloaded glyphs with `sbit.buffer == 0' */ + /* and 'width == 255', 'height == 0' */ + /* */ + if ( error && error != FTC_Err_Out_Of_Memory ) + { + BadGlyph: + sbit->width = 255; + sbit->height = 0; + sbit->buffer = NULL; + error = 0; } return error; } - FT_CALLBACK_DEF( FT_Error ) - ftc_sbit_node_init( FTC_SBitNode snode, - FTC_GlyphQuery gquery, - FTC_Cache cache ) + FT_EXPORT_DEF( FT_Error ) + FTC_SNode_New( FTC_SNode *psnode, + FTC_GQuery gquery, + FTC_Cache cache ) { - FT_Error error; + FT_Memory memory = cache->memory; + FT_Error error; + FTC_SNode snode = NULL; + FT_UInt gindex = gquery->gindex; + FTC_Family family = gquery->family; + FTC_SFamilyClass clazz = FTC_CACHE__SFAMILY_CLASS( cache ); + FT_UInt total; - ftc_glyph_node_init( FTC_GLYPH_NODE( snode ), - gquery->gindex, - FTC_GLYPH_FAMILY( gquery->query.family ) ); + total = clazz->family_get_count( family, cache->manager ); + if ( total == 0 || gindex >= total ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } - error = ftc_sbit_node_load( snode, - cache->manager, - FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ), - gquery->gindex, - NULL ); - if ( error ) - ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache ); + if ( !FT_NEW( snode ) ) + { + FT_UInt count, start; + + start = gindex - (gindex % FTC_SBIT_ITEMS_PER_NODE); + count = total - start; + if ( count > FTC_SBIT_ITEMS_PER_NODE ) + count = FTC_SBIT_ITEMS_PER_NODE; + FTC_GNode_Init( FTC_GNODE( snode ), start, family ); + + snode->count = count; + + error = ftc_snode_load( snode, + cache->manager, + gindex, + NULL ); + if ( error ) + { + FTC_SNode_Free( snode, cache ); + snode = NULL; + } + } + + Exit: + *psnode = snode; return error; } - FT_CALLBACK_DEF( FT_ULong ) - ftc_sbit_node_weight( FTC_SBitNode snode ) + FT_EXPORT_DEF( FT_ULong ) + FTC_SNode_Weight( FTC_SNode snode ) { - FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); - FT_UInt count = gnode->item_count; - FTC_SBit sbit = snode->sbits; - FT_Int pitch; - FT_ULong size; + FT_UInt count = snode->count; + FTC_SBit sbit = snode->sbits; + FT_Int pitch; + FT_ULong size; /* the node itself */ size = sizeof ( *snode ); /* the sbit records */ - size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec ); + size += count * sizeof( FTC_SBitRec ); for ( ; count > 0; count--, sbit++ ) { @@ -285,22 +258,20 @@ } - FT_CALLBACK_DEF( FT_Bool ) - ftc_sbit_node_compare( FTC_SBitNode snode, - FTC_SBitQuery squery, - FTC_Cache cache ) + FT_EXPORT_DEF( FT_Bool ) + FTC_SNode_Compare( FTC_SNode snode, + FTC_GQuery gquery, + FTC_Cache cache ) { - FTC_GlyphQuery gquery = FTC_GLYPH_QUERY( squery ); - FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode ); - FT_Bool result; - + FTC_GNode gnode = FTC_GNODE( snode ); + FT_UInt gindex = gquery->gindex; + FT_Bool result; - result = ftc_glyph_node_compare( gnode, gquery ); + result = FT_BOOL( (FT_UInt)(gindex - gnode->gindex) < snode->count ); if ( result ) { /* check if we need to load the glyph bitmap now */ - FT_UInt gindex = gquery->gindex; - FTC_SBit sbit = snode->sbits + ( gindex - gnode->item_start ); + FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex ); if ( sbit->buffer == NULL && sbit->width != 255 ) @@ -308,247 +279,15 @@ FT_ULong size; - if ( !ftc_sbit_node_load( - snode, cache->manager, - FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ), - gindex, &size ) ) + if ( !ftc_snode_load( snode, cache->manager, + gindex, &size ) ) + { cache->manager->cur_weight += size; + } } } return result; } - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** SBITS FAMILIES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_DEF( FT_Error ) - ftc_sbit_family_init( FTC_SBitFamily sfam, - FTC_SBitQuery squery, - FTC_Cache cache ) - { - FTC_Manager manager = cache->manager; - FT_Error error; - FT_Face face; - - - sfam->type = squery->type; - - /* we need to compute "cquery.item_total" now */ - error = FTC_Manager_Lookup_Face( manager, - squery->type.font.face_id, - &face ); - if ( !error ) - { - error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ), - FTC_IMAGE_TYPE_HASH( &sfam->type ), - FTC_SBIT_ITEMS_PER_NODE, - face->num_glyphs, - FTC_GLYPH_QUERY( squery ), - cache ); - } - - return error; - } - - - FT_CALLBACK_DEF( FT_Bool ) - ftc_sbit_family_compare( FTC_SBitFamily sfam, - FTC_SBitQuery squery ) - { - FT_Bool result; - - - /* we need to set the "cquery.cset" field or our query for */ - /* faster glyph comparisons in ftc_sbit_node_compare */ - /* */ - result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) ); - if ( result ) - FTC_GLYPH_FAMILY_FOUND( sfam, squery ); - - return result; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** SBITS CACHE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - FT_CALLBACK_TABLE_DEF - const FTC_Cache_ClassRec ftc_sbit_cache_class = - { - sizeof ( FTC_CacheRec ), - (FTC_Cache_InitFunc) ftc_cache_init, - (FTC_Cache_ClearFunc)ftc_cache_clear, - (FTC_Cache_DoneFunc) ftc_cache_done, - - sizeof ( FTC_SBitFamilyRec ), - (FTC_Family_InitFunc) ftc_sbit_family_init, - (FTC_Family_CompareFunc)ftc_sbit_family_compare, - (FTC_Family_DoneFunc) ftc_glyph_family_done, - - sizeof ( FTC_SBitNodeRec ), - (FTC_Node_InitFunc) ftc_sbit_node_init, - (FTC_Node_WeightFunc) ftc_sbit_node_weight, - (FTC_Node_CompareFunc)ftc_sbit_node_compare, - (FTC_Node_DoneFunc) ftc_sbit_node_done - }; - - - /* documentation is in ftcsbits.h */ - - FT_EXPORT_DEF( FT_Error ) - FTC_SBitCache_New( FTC_Manager manager, - FTC_SBitCache *acache ) - { - return FTC_Manager_Register_Cache( manager, - &ftc_sbit_cache_class, - (FTC_Cache*)acache ); - } - - - /* documentation is in ftcsbits.h */ - -#ifdef FTC_CACHE_USE_INLINE - -#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \ - ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) ) - -#define GEN_CACHE_NODE_COMPARE( n, q, c ) \ - ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c ) - -#define GEN_CACHE_LOOKUP ftc_sbit_cache_lookup -#include "ftccache.i" - -#else /* !FTC_CACHE_USE_INLINE */ - -#define ftc_sbit_cache_lookup ftc_cache_lookup - -#endif /* !FTC_CACHE_USE_INLINE */ - - 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_SBitQueryRec squery; - FTC_SBitNode node; - - - /* other argument checks delayed to ftc_cache_lookup */ - if ( !ansbit ) - return FTC_Err_Invalid_Argument; - - *ansbit = NULL; - - if ( anode ) - *anode = NULL; - - squery.gquery.gindex = gindex; - squery.type = *type; - - error = ftc_sbit_cache_lookup( FTC_CACHE( cache ), - FTC_QUERY( &squery ), - (FTC_Node*)&node ); - if ( !error ) - { - *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start ); - - if ( anode ) - { - *anode = FTC_NODE( node ); - FTC_NODE( node )->ref_count++; - } - } - return error; - } - - - /* backwards-compatibility functions */ - - FT_EXPORT_DEF( FT_Error ) - FTC_SBit_Cache_New( FTC_Manager manager, - FTC_SBit_Cache *acache ) - { - return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache ); - } - - - FT_EXPORT_DEF( FT_Error ) - FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache, - FTC_Image_Desc* desc, - FT_UInt gindex, - FTC_SBit *ansbit ) - { - FTC_ImageTypeRec type0; - - - if ( !desc ) - return FTC_Err_Invalid_Argument; - - type0.font = desc->font; - type0.flags = 0; - - /* convert image type flags to load flags */ - { - FT_UInt load_flags = FT_LOAD_DEFAULT; - FT_UInt type = desc->image_type; - - - /* determine load flags, depending on the font description's */ - /* image type */ - - if ( ftc_image_format( type ) == ftc_image_format_bitmap ) - { - if ( type & ftc_image_flag_monochrome ) - load_flags |= FT_LOAD_MONOCHROME; - - /* disable embedded bitmaps loading if necessary */ - if ( type & ftc_image_flag_no_sbits ) - load_flags |= FT_LOAD_NO_BITMAP; - } - else - { - /* we want an outline, don't load embedded bitmaps */ - load_flags |= FT_LOAD_NO_BITMAP; - - if ( type & ftc_image_flag_unscaled ) - load_flags |= FT_LOAD_NO_SCALE; - } - - /* always render glyphs to bitmaps */ - load_flags |= FT_LOAD_RENDER; - - if ( type & ftc_image_flag_unhinted ) - load_flags |= FT_LOAD_NO_HINTING; - - if ( type & ftc_image_flag_autohinted ) - load_flags |= FT_LOAD_FORCE_AUTOHINT; - - type0.flags = load_flags; - } - - return FTC_SBitCache_Lookup( (FTC_SBitCache)cache, - &type0, - gindex, - ansbit, - NULL ); - } - - /* END */ diff --git a/src/cache/ftlru.c b/src/cache/ftlru.c deleted file mode 100644 index b25d7419d..000000000 --- a/src/cache/ftlru.c +++ /dev/null @@ -1,390 +0,0 @@ -/***************************************************************************/ -/* */ -/* ftlru.c */ -/* */ -/* Simple LRU list-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 -#include FT_CACHE_H -#include FT_CACHE_INTERNAL_LRU_H -#include FT_LIST_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H - -#include "ftcerror.h" - - - FT_EXPORT_DEF( FT_Error ) - FT_LruList_New( FT_LruList_Class clazz, - FT_UInt max_nodes, - FT_Pointer user_data, - FT_Memory memory, - FT_LruList *alist ) - { - FT_Error error; - FT_LruList list; - - - if ( !alist || !clazz ) - return FTC_Err_Invalid_Argument; - - *alist = NULL; - if ( !FT_ALLOC( list, clazz->list_size ) ) - { - /* initialize common fields */ - list->clazz = clazz; - list->memory = memory; - list->max_nodes = max_nodes; - list->data = user_data; - - if ( clazz->list_init ) - { - error = clazz->list_init( list ); - if ( error ) - { - if ( clazz->list_done ) - clazz->list_done( list ); - - FT_FREE( list ); - } - } - - *alist = list; - } - - return error; - } - - - FT_EXPORT_DEF( void ) - FT_LruList_Destroy( FT_LruList list ) - { - FT_Memory memory; - FT_LruList_Class clazz; - - - if ( !list ) - return; - - memory = list->memory; - clazz = list->clazz; - - FT_LruList_Reset( list ); - - if ( clazz->list_done ) - clazz->list_done( list ); - - FT_FREE( list ); - } - - - FT_EXPORT_DEF( void ) - FT_LruList_Reset( FT_LruList list ) - { - FT_LruNode node; - FT_LruList_Class clazz; - FT_Memory memory; - - - if ( !list ) - return; - - node = list->nodes; - clazz = list->clazz; - memory = list->memory; - - while ( node ) - { - FT_LruNode next = node->next; - - - if ( clazz->node_done ) - clazz->node_done( node, list->data ); - - FT_FREE( node ); - node = next; - } - - list->nodes = NULL; - list->num_nodes = 0; - } - - - FT_EXPORT_DEF( FT_Error ) - FT_LruList_Lookup( FT_LruList list, - FT_LruKey key, - FT_LruNode *anode ) - { - FT_Error error = 0; - FT_LruNode node, *pnode; - FT_LruList_Class clazz; - FT_LruNode result = NULL; - FT_Memory memory; - - - if ( !list || !key || !anode ) - return FTC_Err_Invalid_Argument; - - pnode = &list->nodes; - node = NULL; - clazz = list->clazz; - memory = list->memory; - - if ( clazz->node_compare ) - { - for (;;) - { - node = *pnode; - if ( node == NULL ) - break; - - if ( clazz->node_compare( node, key, list->data ) ) - break; - - pnode = &(*pnode)->next; - } - } - else - { - for (;;) - { - node = *pnode; - if ( node == NULL ) - break; - - if ( node->key == key ) - break; - - pnode = &(*pnode)->next; - } - } - - if ( node ) - { - /* move element to top of list */ - if ( list->nodes != node ) - { - *pnode = node->next; - node->next = list->nodes; - list->nodes = node; - } - result = node; - goto Exit; - } - - /* Since we haven't found the relevant element in our LRU list, - * we're going to "create" a new one. - * - * The following code is a bit special, because it tries to handle - * out-of-memory conditions (OOM) in an intelligent way. - * - * More precisely, if not enough memory is available to create a - * new node or "flush" an old one, we need to remove the oldest - * elements from our list, and try again. Since several tries may - * be necessary, a loop is needed. - * - * This loop will only exit when: - * - * - a new node was successfully created, or an old node flushed - * - an error other than FTC_Err_Out_Of_Memory is detected - * - the list of nodes is empty, and it isn't possible to create - * new nodes - * - * On each unsuccessful attempt, one node will be removed from the list. - * - */ - - { - FT_Int drop_last = ( list->max_nodes > 0 && - list->num_nodes >= list->max_nodes ); - - for (;;) - { - node = NULL; - - /* If "drop_last" is true, we should free the last node in - * the list to make room for a new one. Note that we reuse - * its memory block to save allocation calls. - */ - if ( drop_last ) - { - /* find the last node in the list - */ - pnode = &list->nodes; - node = *pnode; - - if ( node == NULL ) - { - FT_ASSERT( list->num_nodes == 0 ); - error = FTC_Err_Out_Of_Memory; - goto Exit; - } - - FT_ASSERT( list->num_nodes > 0 ); - - while ( node->next ) - { - pnode = &node->next; - node = *pnode; - } - - /* Remove it from the list, and try to "flush" it. Doing this will - * save a significant number of dynamic allocations compared to - * a classic destroy/create cycle. - */ - *pnode = NULL; - list->num_nodes--; - - if ( clazz->node_flush ) - { - error = clazz->node_flush( node, key, list->data ); - if ( !error ) - goto Success; - - /* Note that if an error occured during the flush, we need to - * finalize it since it is potentially in incomplete state. - */ - } - - /* We finalize, but do not destroy the last node, we - * simply reuse its memory block! - */ - if ( clazz->node_done ) - clazz->node_done( node, list->data ); - - FT_MEM_ZERO( node, clazz->node_size ); - } - else - { - /* Try to allocate a new node when "drop_last" is not TRUE. - * This usually happens on the first pass, when the LRU list - * is not already full. - */ - if ( FT_ALLOC( node, clazz->node_size ) ) - goto Fail; - } - - FT_ASSERT( node != NULL ); - - node->key = key; - error = clazz->node_init( node, key, list->data ); - if ( error ) - { - if ( clazz->node_done ) - clazz->node_done( node, list->data ); - - FT_FREE( node ); - goto Fail; - } - - Success: - result = node; - - node->next = list->nodes; - list->nodes = node; - list->num_nodes++; - goto Exit; - - Fail: - if ( error != FTC_Err_Out_Of_Memory ) - goto Exit; - - drop_last = 1; - continue; - } - } - - Exit: - *anode = result; - return error; - } - - - FT_EXPORT_DEF( void ) - FT_LruList_Remove( FT_LruList list, - FT_LruNode node ) - { - FT_LruNode *pnode; - - - if ( !list || !node ) - return; - - pnode = &list->nodes; - for (;;) - { - if ( *pnode == node ) - { - FT_Memory memory = list->memory; - FT_LruList_Class clazz = list->clazz; - - - *pnode = node->next; - node->next = NULL; - - if ( clazz->node_done ) - clazz->node_done( node, list->data ); - - FT_FREE( node ); - list->num_nodes--; - break; - } - - pnode = &(*pnode)->next; - } - } - - - FT_EXPORT_DEF( void ) - FT_LruList_Remove_Selection( FT_LruList list, - FT_LruNode_SelectFunc select_func, - FT_Pointer select_data ) - { - FT_LruNode *pnode, node; - FT_LruList_Class clazz; - FT_Memory memory; - - - if ( !list || !select_func ) - return; - - memory = list->memory; - clazz = list->clazz; - pnode = &list->nodes; - - for (;;) - { - node = *pnode; - if ( node == NULL ) - break; - - if ( select_func( node, select_data, list->data ) ) - { - *pnode = node->next; - node->next = NULL; - - if ( clazz->node_done ) - clazz->node_done( node, list ); - - FT_FREE( node ); - list->num_nodes--; - } - else - pnode = &(*pnode)->next; - } - } - - -/* END */ diff --git a/src/cache/rules.mk b/src/cache/rules.mk index 617ca48da..154f126dc 100644 --- a/src/cache/rules.mk +++ b/src/cache/rules.mk @@ -25,8 +25,9 @@ CACHE_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(CACHE_DIR)) # Cache driver sources (i.e., C files) # -CACHE_DRV_SRC := $(CACHE_DIR)/ftlru.c \ +CACHE_DRV_SRC := $(CACHE_DIR)/ftcmru.c \ $(CACHE_DIR)/ftcmanag.c \ + $(CACHE_DIR)/ftcbasic.c \ $(CACHE_DIR)/ftccache.c \ $(CACHE_DIR)/ftcglyph.c \ $(CACHE_DIR)/ftcsbits.c \ @@ -35,10 +36,11 @@ CACHE_DRV_SRC := $(CACHE_DIR)/ftlru.c \ # Cache driver headers # -CACHE_DRV_H := $(CACHE_H_DIR)/ftlru.h \ +CACHE_DRV_H := $(CACHE_H_DIR)/ftcmru.h \ $(CACHE_H_DIR)/ftcmanag.h \ $(CACHE_H_DIR)/ftcglyph.h \ $(CACHE_H_DIR)/ftcimage.h \ + $(CACHE_H_DIR)/ftccmap.h \ $(CACHE_DIR)/ftcerror.h