new version of the cache sub-system - still under debugging

This commit is contained in:
David Turner 2003-12-19 21:23:58 +00:00
parent 9e185f32ce
commit 57ecae22a7
28 changed files with 2959 additions and 3520 deletions

View File

@ -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,82 +73,12 @@ 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 *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct FTC_FamilyRec_
{
FT_LruNodeRec lru;
FTC_Cache cache;
FT_UInt num_nodes;
FT_UInt fam_index;
} FTC_FamilyRec;
#define FTC_FAMILY( x ) ( (FTC_Family)(x) )
#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) )
/*************************************************************************/
/* */
/* 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. */
/* */
/* 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 );
/* 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 );
/*************************************************************************/
/*************************************************************************/
@ -168,23 +88,57 @@ FT_BEGIN_HEADER
/*************************************************************************/
/*************************************************************************/
/* initialize a new cache node */
typedef FT_Error (*FTC_Node_NewFunc)( FTC_Node *pnode,
FT_Pointer query,
FTC_Cache cache );
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 );
typedef void (*FTC_Node_FreeFunc)( FTC_Node node,
FTC_Cache cache );
typedef FT_Error (*FTC_Cache_InitFunc)( FTC_Cache cache );
typedef void (*FTC_Cache_DoneFunc)( FTC_Cache cache );
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;
} 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 );
/* can be used directly as FTC_Cache_ClearFunc(), or called by custom */
/* cache clear routines */
FT_EXPORT( void )
ftc_cache_clear( FTC_Cache cache );
/* initalize the hash table within the cache */
/* default cache initialize */
FT_EXPORT( FT_Error )
ftc_cache_init( FTC_Cache cache );
FTC_Cache_Init( FTC_Cache cache );
/* can be called when the key's hash value has been computed */
/* default cache finalizer */
FT_EXPORT( void )
FTC_Cache_Done( FTC_Cache 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_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 );
/* */

View File

@ -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 <ft2build.h>
#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 */
FT_UInt gindex;
FTC_Family family;
} FTC_GlyphFamilyRec;
} FTC_GQueryRec, *FTC_GQuery;
#define FTC_GQUERY( x ) ( (FTC_GQuery)(x) )
#define FTC_GLYPH_FAMILY( x ) ( (FTC_GlyphFamily)(x) )
#define FTC_GLYPH_FAMILY_P( x ) ( (FTC_GlyphFamily*)(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,37 +185,79 @@ 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 );
/* must be called by derived FTC_Family_InitFunc; */
/* calls "ftc_family_init" */
typedef struct FTC_GCacheRec_
{
FTC_CacheRec cache;
FTC_MruListRec families;
} FTC_GCacheRec, *FTC_GCache;
#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 );
/* */
FT_END_HEADER

View File

@ -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 <ft2build.h>
#include FT_CACHE_H
#include FT_CACHE_INTERNAL_GLYPH_H
FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* <Section> */
/* cache_subsystem */
/* */
/*************************************************************************/
/* the FT_Glyph image node type - we store only 1 glyph per node */
typedef struct FTC_INodeRec_
{
FTC_GNodeRec gnode;
FT_Glyph glyph;
} FTC_INodeRec, *FTC_INode;
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** IMAGE CACHE OBJECT *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#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
typedef FT_Error (*FTC_IFamily_LoadGlyphFunc)( FTC_Family family,
FT_UInt gindex,
FTC_Cache cache,
FT_Glyph *aglyph );
/**************************************************************************
*
* @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_IFamilyClassRec_
{
FTC_MruListClassRec clazz;
FTC_IFamily_LoadGlyphFunc family_load_glyph;
} FTC_IFamilyClassRec;
typedef const FTC_IFamilyClassRec* FTC_IFamilyClass;
#define FTC_IFAMILY_CLASS(x) ((FTC_IFamilyClass)(x))
#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 );
/* 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
*/
typedef struct FTC_ImageTypeRec_
{
FTC_FontRec font;
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 ) )
/*************************************************************************/
/* */
/* <Type> */
/* FTC_ImageCache */
/* */
/* <Description> */
/* 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;
/*************************************************************************/
/* */
/* <Function> */
/* FTC_ImageCache_New */
/* */
/* <Description> */
/* Creates a new glyph image cache. */
/* */
/* <Input> */
/* manager :: The parent manager for the image cache. */
/* */
/* <Output> */
/* acache :: A handle to the new glyph image cache object. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FTC_ImageCache_New( FTC_Manager manager,
FTC_ImageCache *acache );
FTC_INode_New( FTC_INode *pinode,
FTC_GQuery gquery,
FTC_Cache cache );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_ImageCache_Lookup */
/* */
/* <Description> */
/* Retrieves a given glyph image from a glyph image cache. */
/* */
/* <Input> */
/* cache :: A handle to the source glyph image cache. */
/* */
/* type :: A pointer to a glyph image type descriptor. */
/* */
/* gindex :: The glyph index to retrieve. */
/* */
/* <Output> */
/* 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). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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
/*************************************************************************/
/* */
/* <Struct> */
/* FTC_Image_Desc */
/* */
/* <Description> */
/* THIS TYPE IS DEPRECATED. Use @FTC_ImageTypeRec instead. */
/* */
/* A simple structure used to describe a given glyph image category. */
/* */
/* <Fields> */
/* 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_
{
FTC_FontRec font;
FT_UInt image_type;
} FTC_Image_Desc;
/*************************************************************************/
/* */
/* <Type> */
/* FTC_Image_Cache */
/* */
/* <Description> */
/* THIS TYPE IS DEPRECATED. Use @FTC_ImageCache instead. */
/* */
typedef FTC_ImageCache FTC_Image_Cache;
/*************************************************************************/
/* */
/* <Function> */
/* FTC_Image_Cache_New */
/* */
/* <Description> */
/* THIS FUNCTION IS DEPRECATED. Use @FTC_ImageCache_New instead. */
/* */
/* Creates a new glyph image cache. */
/* */
/* <Input> */
/* manager :: The parent manager for the image cache. */
/* */
/* <Output> */
/* acache :: A handle to the new glyph image cache object. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FTC_Image_Cache_New( FTC_Manager manager,
FTC_Image_Cache *acache );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_Image_Cache_Lookup */
/* */
/* <Description> */
/* THIS FUNCTION IS DEPRECATED. Use @FTC_ImageCache_Lookup instead. */
/* */
/* <Input> */
/* cache :: A handle to the source glyph image cache. */
/* */
/* desc :: A pointer to a glyph image descriptor. */
/* */
/* gindex :: The glyph index to retrieve. */
/* */
/* <Output> */
/* aglyph :: The corresponding @FT_Glyph object. 0 in case of */
/* failure. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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. */
/* */
FT_EXPORT( FT_Error )
FTC_Image_Cache_Lookup( FTC_Image_Cache cache,
FTC_Image_Desc* desc,
FT_UInt gindex,
FT_Glyph *aglyph );
/* can be used as @FTC_Node_WeightFunc */
FT_EXPORT( FT_ULong )
FTC_INode_Weight( FTC_INode inode );
/* */
FT_END_HEADER
#endif /* __FTCIMAGE_H__ */

View File

@ -65,7 +65,7 @@
#include <ft2build.h>
#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 );
/*************************************************************************/
/* */
/* <Struct> */
/* FTC_ManagerRec */
/* */
/* <Description> */
/* The cache manager structure. */
/* */
/* <Fields> */
/* 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 );
/* */
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;
/* can be called to increment a node's reference count */
FT_EXPORT( void )
FTC_Node_Ref( 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 )
/*************************************************************************/
/* */
/* <Function> */
/* FTC_Node_Unref */
/* */
/* <Description> */
/* Decrement a cache node's internal reference count. When the count */
/* reaches 0, it is not destroyed but becomes eligible for subsequent */
/* cache flushes. */
/* */
/* <Input> */
/* node :: The cache node handle. */
/* */
/* manager :: The cache manager handle. */
/* */
FT_EXPORT( void )
FTC_Node_Unref( FTC_Node node,
FTC_Manager manager );
FT_EXPORT( FT_Error )
FTC_Manager_LookupSize( FTC_Manager manager,
FTC_Scaler scaler,
FT_Size *asize );
/* */
FT_END_HEADER
#endif /* __FTCMANAG_H__ */

143
include/freetype/cache/ftcmru.h vendored Normal file
View File

@ -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 <ft2build.h>
#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 */

View File

@ -22,251 +22,69 @@
#include <ft2build.h>
#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
/*************************************************************************/
/* */
/* <Section> */
/* cache_subsystem */
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* <Type> */
/* FTC_SBit */
/* */
/* <Description> */
/* A handle to a small bitmap descriptor. See the @FTC_SBitRec */
/* structure for details. */
/* */
typedef struct FTC_SBitRec_* FTC_SBit;
/*************************************************************************/
/* */
/* <Struct> */
/* FTC_SBitRec */
/* */
/* <Description> */
/* A very compact structure used to describe a small glyph bitmap. */
/* */
/* <Fields> */
/* 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_
typedef struct FTC_SNodeRec_
{
FT_Byte width;
FT_Byte height;
FT_Char left;
FT_Char top;
FTC_GNodeRec gnode;
FT_UInt count;
FTC_SBitRec sbits[ FTC_SBIT_ITEMS_PER_NODE ];
FT_Byte format;
FT_Byte max_grays;
FT_Short pitch;
FT_Char xadvance;
FT_Char yadvance;
FT_Byte* buffer;
} FTC_SBitRec;
} FTC_SNodeRec, *FTC_SNode;
/*************************************************************************/
/* */
/* <Type> */
/* FTC_SBitCache */
/* */
/* <Description> */
/* 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;
#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
typedef FT_UInt (*FTC_SFamily_GetCountFunc)( FTC_Family family,
FTC_Manager manager );
/*************************************************************************/
/* */
/* <Type> */
/* FTC_SBit_Cache */
/* */
/* <Description> */
/* DEPRECATED. Use @FTC_SBitCache instead. */
/* */
typedef FTC_SBitCache FTC_SBit_Cache;
typedef FT_Error (*FTC_SFamily_LoadGlyphFunc)( FTC_Family family,
FT_UInt gindex,
FTC_Manager manager,
FT_Face *aface );
typedef struct FTC_SFamilyClassRec_
{
FTC_MruListClassRec clazz;
FTC_SFamily_GetCountFunc family_get_count;
FTC_SFamily_LoadGlyphFunc family_load_glyph;
} FTC_SFamilyClassRec;
typedef const FTC_SFamilyClassRec* FTC_SFamilyClass;
#define FTC_SFAMILY_CLASS(x) ((FTC_SFamilyClass)(x))
#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 );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBitCache_New */
/* */
/* <Description> */
/* Creates a new cache to store small glyph bitmaps. */
/* */
/* <Input> */
/* manager :: A handle to the source cache manager. */
/* */
/* <Output> */
/* acache :: A handle to the new sbit cache. NULL in case of error. */
/* */
/* <Return> */
/* 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 );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBitCache_Lookup */
/* */
/* <Description> */
/* Looks up a given small glyph bitmap in a given sbit cache and */
/* "lock" it to prevent its flushing from the cache until needed */
/* */
/* <Input> */
/* cache :: A handle to the source sbit cache. */
/* */
/* type :: A pointer to the glyph image type descriptor. */
/* */
/* gindex :: The glyph index. */
/* */
/* <Output> */
/* 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). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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 );
/* */
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBit_Cache_New */
/* */
/* <Description> */
/* DEPRECATED. Use @FTC_SBitCache_New instead. */
/* */
/* Creates a new cache to store small glyph bitmaps. */
/* */
/* <Input> */
/* manager :: A handle to the source cache manager. */
/* */
/* <Output> */
/* acache :: A handle to the new sbit cache. NULL in case of error. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FTC_SBit_Cache_New( FTC_Manager manager,
FTC_SBit_Cache *acache );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBit_Cache_Lookup */
/* */
/* <Description> */
/* DEPRECATED. Use @FTC_SBitCache_Lookup instead. */
/* */
/* Looks up a given small glyph bitmap in a given sbit cache. */
/* */
/* <Input> */
/* cache :: A handle to the source sbit cache. */
/* */
/* desc :: A pointer to the glyph image descriptor. */
/* */
/* gindex :: The glyph index. */
/* */
/* <Output> */
/* sbit :: A handle to a small bitmap descriptor. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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__ */

View File

@ -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 <ft2build.h>
#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 */

View File

@ -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 <freetype/cache/ftcimage.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 <freetype/cache/ftcsbits.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 <freetype/cache/ftccmap.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 <freetype/cache/ftcmanag.h>
#define FT_CACHE_INTERNAL_LRU_H <freetype/cache/ftlru.h>
#define FT_CACHE_INTERNAL_GLYPH_H <freetype/cache/ftcglyph.h>
#define FT_CACHE_INTERNAL_MRU_H <freetype/cache/ftcmru.h>
#define FT_CACHE_INTERNAL_MANAGER_H <freetype/cache/ftcmanag.h>
#define FT_CACHE_INTERNAL_CACHE_H <freetype/cache/ftccache.h>
#define FT_CACHE_INTERNAL_GLYPH_H <freetype/cache/ftcglyph.h>
#define FT_CACHE_INTERNAL_IMAGE_H <freetype/cache/ftcimage.h>
#define FT_CACHE_INTERNAL_SBITS_H <freetype/cache/ftcsbits.h>
#define FT_XFREE86_H <freetype/ftxf86.h>

View File

@ -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
/*************************************************************************/

View File

@ -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. */
/* */
/* <Input> */
/* 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). */
/* */
/* <Output> */
/* amanager :: A handle to a new manager object. 0 in case of */
@ -331,7 +319,7 @@ FT_BEGIN_HEADER
/*************************************************************************/
/* */
/* <Function> */
/* FTC_Manager_Lookup_Face */
/* FTC_Manager_LookupFace */
/* */
/* <Description> */
/* 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
/*************************************************************************/
/* */
/* <Function> */
/* FTC_Manager_Lookup_Size */
/* FTC_Node_Unref */
/* */
/* <Description> */
/* 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. */
/* */
/* <Input> */
/* 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 );
/*************************************************************************/
/* */
/* <Section> */
/* 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 );
/*************************************************************************/
/* */
/* <Section> */
/* 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 ) )
/*************************************************************************/
/* */
/* <Type> */
/* FTC_ImageCache */
/* */
/* <Description> */
/* 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;
/*************************************************************************/
/* */
/* <Function> */
/* FTC_ImageCache_New */
/* */
/* <Description> */
/* Creates a new glyph image cache. */
/* */
/* <Input> */
/* manager :: The parent manager for the image cache. */
/* */
/* <Output> */
/* aface :: A pointer to the handle of the face object. Set it to */
/* zero if you don't need it. */
/* acache :: A handle to the new glyph image cache object. */
/* */
/* asize :: A pointer to the handle of the size object. Set it to */
/* zero if you don't need it. */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FTC_ImageCache_New( FTC_Manager manager,
FTC_ImageCache *acache );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_ImageCache_Lookup */
/* */
/* <Description> */
/* Retrieves a given glyph image from a glyph image cache. */
/* */
/* <Input> */
/* cache :: A handle to the source glyph image cache. */
/* */
/* type :: A pointer to a glyph image type descriptor. */
/* */
/* gindex :: The glyph index to retrieve. */
/* */
/* <Output> */
/* 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). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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. */
/* */
/* 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! */
/* */
/* 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. */
/* 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_Manager_Lookup_Size( FTC_Manager manager,
FTC_Font font,
FT_Face *aface,
FT_Size *asize );
FTC_ImageCache_Lookup( FTC_ImageCache cache,
FTC_ImageType type,
FT_UInt gindex,
FT_Glyph *aglyph,
FTC_Node *anode );
/*************************************************************************/
/* */
/* <Section> */
/* cache_subsystem */
/* */
/*************************************************************************/
/*************************************************************************/
/* */
/* <Type> */
/* FTC_SBit */
/* */
/* <Description> */
/* A handle to a small bitmap descriptor. See the @FTC_SBitRec */
/* structure for details. */
/* */
typedef struct FTC_SBitRec_* FTC_SBit;
/*************************************************************************/
/* */
/* <Struct> */
/* FTC_SBitRec */
/* */
/* <Description> */
/* A very compact structure used to describe a small glyph bitmap. */
/* */
/* <Fields> */
/* 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;
/*************************************************************************/
/* */
/* <Type> */
/* FTC_SBitCache */
/* */
/* <Description> */
/* 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;
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBitCache_New */
/* */
/* <Description> */
/* Creates a new cache to store small glyph bitmaps. */
/* */
/* <Input> */
/* manager :: A handle to the source cache manager. */
/* */
/* <Output> */
/* acache :: A handle to the new sbit cache. NULL in case of error. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FTC_SBitCache_New( FTC_Manager manager,
FTC_SBitCache *acache );
/*************************************************************************/
/* */
/* <Function> */
/* FTC_SBitCache_Lookup */
/* */
/* <Description> */
/* Looks up a given small glyph bitmap in a given sbit cache and */
/* "lock" it to prevent its flushing from the cache until needed */
/* */
/* <Input> */
/* cache :: A handle to the source sbit cache. */
/* */
/* type :: A pointer to the glyph image type descriptor. */
/* */
/* gindex :: The glyph index. */
/* */
/* <Output> */
/* 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). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
/* <Note> */
/* 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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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_
{

View File

@ -19,10 +19,31 @@
#include <ft2build.h>
#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;
@ -1455,18 +1506,33 @@
}
FT_EXPORT_DEF( void )
FT_Stroker_ExportBorder( FT_Stroker stroker,
FT_StrokerBorder border,
FT_Outline* outline )
{
if ( border == FT_STROKER_BORDER_LEFT ||
border == FT_STROKER_BORDER_RIGHT )
{
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 )
{
if ( stroker->valid )
{
ft_stroke_border_export( stroker->borders + 0, outline );
ft_stroke_border_export( stroker->borders + 1, 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.

10
src/cache/Jamfile vendored
View File

@ -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
{

6
src/cache/ftcache.c vendored
View File

@ -19,13 +19,13 @@
#define FT_MAKE_OPTION_SINGLE_OBJECT
#include <ft2build.h>
#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 */

380
src/cache/ftcbasic.c vendored Normal file
View File

@ -0,0 +1,380 @@
#include <ft2build.h>
#include FT_CACHE_H
#include FT_CACHE_INTERNAL_GLYPH_H
#include FT_CACHE_INTERNAL_IMAGE_H
#include FT_CACHE_INTERNAL_SBITS_H
#include FT_INTERNAL_MEMORY_H
#include "ftcerror.h"
/*
* Basic Families
*
*
*/
typedef struct FTC_BasicAttrRec_
{
FTC_ScalerRec scaler;
FT_UInt load_flags;
} FTC_BasicAttrRec, *FTC_BasicAttrs;
#define FTC_BASIC_ATTR_COMPARE(a,b) \
( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
(a)->load_flags == (b)->load_flags )
#define FTC_BASIC_ATTR_HASH(a) \
( FTC_SCALER_HASH(&(a)->scaler) + 31*(a)->load_flags )
typedef struct FTC_BasicQueryRec_
{
FTC_GQueryRec gquery;
FTC_BasicAttrRec attrs;
} FTC_BasicQueryRec, *FTC_BasicQuery;
typedef struct FTC_BasicFamilyRec_
{
FTC_FamilyRec family;
FTC_BasicAttrRec attrs;
} FTC_BasicFamilyRec, *FTC_BasicFamily;
static FT_Bool
ftc_basic_family_compare( FTC_BasicFamily family,
FTC_BasicQuery query )
{
return FT_BOOL( FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs ) );
}
static FT_Error
ftc_basic_family_init( FTC_BasicFamily family,
FTC_BasicQuery query,
FTC_Cache cache )
{
ftc_family_init( FTC_FAMILY( family ), cache );
family->attrs = query->attrs;
return 0;
}
static FT_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;
}

816
src/cache/ftccache.c vendored
View File

@ -17,7 +17,7 @@
#include <ft2build.h>
#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 );
*pnode = node0->link;
node0->link = NULL;
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;
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 )
cache->memory = NULL;
}
}
static void
ftc_cache_add( FTC_Cache cache,
FT_UInt32 hash,
FTC_Node node )
{
node->hash = hash;
ftc_node_hash_link( node, cache );
ftc_node_mru_link( node, cache->manager );
{
FTC_Manager manager = cache->manager;
manager->cur_weight += cache->clazz.node_weight( node, cache );
if ( manager->cur_weight >= manager->max_weight )
{
FT_LruList_Destroy( cache->families );
cache->families = NULL;
node->ref_count++;
FTC_Manager_Compress( manager );
node->ref_count--;
}
}
}
/* 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,
FT_EXPORT( FT_Error )
FTC_Cache_Lookup( FTC_Cache cache,
FT_UInt32 hash,
FT_Pointer query,
FTC_Node *anode )
{
FT_Error error = FTC_Err_Ok;
FTC_Manager manager;
FT_LruNode lru;
FT_UInt free_count = 0;
FT_UFast idx;
FTC_Node* bucket;
FTC_Node* pnode;
FTC_Node node;
FT_Error error = 0;
FTC_Node_CompareFunc compare = cache->clazz.node_compare;
if ( !cache || !query || !anode )
return FTC_Err_Invalid_Argument;
if ( cache == NULL || anode == NULL )
return FT_Err_Invalid_Argument;
*anode = NULL;
query->hash = 0;
query->family = NULL;
manager = cache->manager;
/* 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.
*/
idx = hash & cache->mask;
if ( idx < cache->p )
idx = hash & ( cache->mask * 2 + 1 );
bucket = cache->buckets + idx;
pnode = bucket;
for (;;)
{
node = *pnode;
if ( node == NULL )
goto NewNode;
if ( node->hash == hash && compare( node, query, cache ) )
break;
pnode = &node->link;
}
if ( node != *bucket )
{
*pnode = node->link;
node->link = *bucket;
*bucket = node;
}
/* move to head of MRU list */
{
FTC_Manager manager = cache->manager;
if ( node != manager->nodes_list )
ftc_node_mru_up( node, manager );
}
goto Exit;
NewNode:
/*
* try to allocate a new cache node. Note that in case of
* out-of-memory error (OOM), we'll flush the cache a bit,
* then try again.
*
* on each try, the "tries" variable gives the number
* of old nodes we want to flush from the manager's global list
* before the next allocation attempt. it barely doubles on
* each iteration
*
*/
error = cache->clazz.node_new( &node, query, cache );
if ( !error )
goto AddNode;
node = NULL;
if ( error != FT_Err_Out_Of_Memory )
goto Exit;
{
FTC_Manager manager = cache->manager;
FT_UInt count, tries = 1;
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;
error = cache->clazz.node_new( &node, query, cache );
if ( !error )
break;
pfam = &list->nodes;
for (;;)
{
fam = *pfam;
if ( fam == NULL )
{
error = FT_LruList_Lookup( list, query, &lru );
if ( error )
goto Fail;
goto Skip;
}
if ( compare( fam, query, list->data ) )
break;
pfam = &fam->next;
}
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;
}
lru = fam;
Skip:
;
}
{
FTC_Family family = (FTC_Family) lru;
FT_UFast hash = query->hash;
FTC_Node* bucket;
FT_UInt idx;
idx = hash & cache->mask;
if ( idx < cache->p )
idx = hash & ( cache->mask * 2 + 1 );
bucket = cache->buckets + idx;
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 ( *bucket )
{
FTC_Node* pnode = bucket;
FTC_Node_CompareFunc compare = cache->clazz->node_compare;
for ( ;; )
{
FTC_Node node;
node = *pnode;
if ( node == NULL )
break;
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;
}
/* move to head of MRU list */
if ( node != manager->nodes_list )
ftc_node_mru_up( node, manager );
*anode = node;
goto Exit;
}
pnode = &node->link;
}
}
/* didn't find a node, create a new one */
{
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;
}
/* all is well, exit now
*/
goto Exit;
}
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;
new_count = 1 + free_count * 2;
/* check overflow and bounds */
if ( new_count < free_count || free_count > manager->num_nodes )
node = NULL;
if ( error != FT_Err_Out_Of_Memory )
goto Exit;
free_count = new_count;
count = FTC_Manager_FlushN( manager, tries );
if ( count == 0 )
goto Exit;
/* try to remove "new_count" nodes from the list */
if ( count == tries )
{
FTC_Node first = manager->nodes_list;
FTC_Node node;
if ( first == NULL ) /* empty list! */
goto Exit;
/* 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;
/* 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;
break;
}
ftc_node_destroy( node, manager );
if ( node == first )
break;
node = prev;
}
count = tries*2;
if ( count < tries || count > manager->num_nodes )
count = manager->num_nodes;
}
tries = 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;
}
FT_EXPORT( void )
FTC_Cache_RemoveFaceID( FTC_Cache cache,
FTC_FaceID face_id )
{
FT_UFast i, count;
FTC_Manager manager = cache->manager;
FTC_Node free = NULL;
count = cache->p + cache->mask;
for ( i = 0; i < count; i++ )
{
FTC_Node* bucket = cache->buckets + i;
FTC_Node* pnode = bucket;
for ( ;; )
{
FTC_Node node = *pnode;
if ( node == NULL )
break;
if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
{
*pnode = node->link;
node->link = free;
free = node;
}
else
pnode = &node->link;
}
}
/* remove all nodes in the free list
*/
while ( free )
{
FTC_Node node;
node = free;
free = node->link;
manager->cur_weight -= cache->clazz.node_weight( node, cache );
ftc_node_mru_unlink( node, manager );
cache->clazz.node_free( node, cache );
cache->slack ++;
}
ftc_cache_resize( cache );
}
/* END */

404
src/cache/ftccmap.c vendored
View File

@ -19,8 +19,7 @@
#include <ft2build.h>
#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;
/* 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;
cnode->first = first;
for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
cnode->indices[n] = FTC_CMAP_UNKNOWN;
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;
return 0;
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 )
ftc_cmap_node_compare( FTC_CMapNode node,
FTC_CMapQuery query )
{
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_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 )
hash = FTC_CMAP_HASH( face_id, cmap_index, char_code );
error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
if ( error )
goto Exit;
FT_ASSERT( (FT_UInt)( char_code - node->first ) < FTC_CMAP_INDICES_MAX );
gindex = node->indices[ char_code - node->first ];
if ( gindex == FTC_CMAP_UNKNOWN )
{
FT_UInt offset = (FT_UInt)( char_code - node->first );
FT_Face face;
gindex = 0;
FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
error = FTC_Manager_LookupFace( cache->manager, node->face_id, &face );
if ( error )
goto Exit;
gindex = node->indices[offset];
if ( gindex == FTC_CMAP_UNKNOWN )
if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps )
{
FT_Face face;
FT_CharMap old, cmap = NULL;
old = face->charmap;
cmap = face->charmaps[ cmap_index ];
/* we need to use FT_Get_Char_Index */
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;
/* save old charmap, select new one */
old = face->charmap;
cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
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 */

123
src/cache/ftcglyph.c vendored
View File

@ -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->item_start = (FT_UShort)start;
len = gfam->item_total - start;
if ( len > gfam->item_count )
len = gfam->item_count;
gnode->item_count = (FT_UShort)len;
gfam->family.num_nodes++;
gnode->family = family;
gnode->gindex = gindex;
family->num_nodes++;
}
FT_EXPORT_DEF( void )
ftc_glyph_node_done( FTC_GlyphNode gnode,
FTC_Cache cache )
FTC_GNode_UnselectFamily( FTC_GNode gnode,
FTC_Cache cache )
{
FTC_Family family = gnode->family;
gnode->family = NULL;
if ( family && --family->num_nodes <= 0 )
FTC_MruList_Remove( & FTC_GCACHE(cache)->families, (FTC_MruNode)family );
}
FT_EXPORT_DEF( void )
FTC_GNode_Done( FTC_GNode gnode,
FTC_Cache cache )
{
/* finalize the node */
gnode->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_family_done( FTC_FAMILY( gfam ) );
FTC_Cache_Done( (FTC_Cache)cache );
FTC_MruList_Done( &cache->families );
}
FT_EXPORT_DEF( FT_Error )
FTC_GCache_New( FTC_Manager manager,
FTC_GCacheClass clazz,
FTC_GCache *acache )
{
return FTC_Manager_RegisterCache( manager, (FTC_CacheClass) clazz,
(FTC_Cache*) acache );
}
FT_EXPORT_DEF( FT_Error )
FTC_GCache_Lookup( FTC_GCache cache,
FT_UInt32 hash,
FT_UInt gindex,
FTC_GQuery query,
FTC_Node *anode )
{
FT_Error error;
query->gindex = gindex;
error = FTC_MruList_Lookup( &cache->families, query,
(FTC_MruNode*) &query->family );
if ( !error )
error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, anode );
return error;
}

338
src/cache/ftcimage.c vendored
View File

@ -18,133 +18,60 @@
#include <ft2build.h>
#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 */

685
src/cache/ftcmanag.c vendored
View File

@ -18,8 +18,7 @@
#include <ft2build.h>
#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,41 +32,166 @@
#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
static FT_Error
ftc_scaler_lookup_size( FTC_Manager manager,
FTC_Scaler scaler,
FT_Size *asize )
{
FT_Face face;
FT_Size size = NULL;
FT_Error error;
error = FTC_Manager_LookupFace( manager, scaler->face_id, &face );
if ( error ) goto Exit;
error = FT_New_Size( face, &size );
if ( error ) goto Exit;
FT_Activate_Size( size );
if ( scaler->pixel )
error = FT_Set_Pixel_Sizes( face, scaler->width, scaler->height );
else
error = FT_Set_Char_Size( face, scaler->width, scaler->height,
scaler->x_res, scaler->y_res );
if ( error )
{
FT_Done_Size( size );
size = NULL;
}
Exit:
*asize = size;
return error;
}
typedef struct FTC_SizeNodeRec_
{
FTC_MruNodeRec node;
FT_Size size;
FTC_ScalerRec scaler;
} FTC_SizeNodeRec, *FTC_SizeNode;
FT_CALLBACK_DEF( void )
ftc_size_node_done( FTC_SizeNode node )
{
FT_Size size = node->size;
if ( size )
FT_Done_Size( size );
}
FT_CALLBACK_DEF( FT_Bool )
ftc_size_node_compare( FTC_SizeNode node,
FTC_Scaler scaler )
{
FTC_Scaler scaler0 = &node->scaler;
return FTC_SCALER_COMPARE( scaler0, scaler );
}
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_init( FTC_SizeNode node,
FTC_Scaler scaler,
FTC_Manager manager )
{
node->scaler = scaler[0];
return ftc_scaler_lookup_size( manager, scaler, &node->size );
}
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_reset( FTC_SizeNode node,
FTC_Scaler scaler,
FTC_Manager manager )
{
FT_Done_Size( node->size );
node->scaler = scaler[0];
return ftc_scaler_lookup_size( manager, scaler, &node->size );
}
static const FTC_MruListClassRec ftc_size_list_class =
{
sizeof( FTC_SizeNodeRec ),
(FTC_MruNode_CompareFunc) ftc_size_node_compare,
(FTC_MruNode_InitFunc) ftc_size_node_init,
(FTC_MruNode_ResetFunc) ftc_size_node_reset,
(FTC_MruNode_DoneFunc) ftc_size_node_done
};
/* helper function used by ftc_face_node_done */
static FT_Bool
ftc_size_node_compare_faceid( FTC_SizeNode node,
FTC_FaceID face_id )
{
return FT_BOOL( node->scaler.face_id == face_id );
}
FT_EXPORT_DEF( FT_Error )
FTC_Manager_LookupSize( FTC_Manager manager,
FTC_Scaler scaler,
FT_Size *asize )
{
FT_Error error;
FTC_SizeNode node;
if ( asize == NULL )
return FTC_Err_Bad_Argument;
*asize = NULL;
if ( !manager )
return FTC_Err_Invalid_Cache_Handle;
error = FTC_MruList_Lookup( &manager->sizes,
scaler,
(FTC_MruNode*) &node );
if ( !error )
*asize = node->size;
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FACE LRU IMPLEMENTATION *****/
/***** FACE MRU IMPLEMENTATION *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct FTC_FaceNodeRec_* FTC_FaceNode;
typedef struct FTC_SizeNodeRec_* FTC_SizeNode;
typedef struct FTC_FaceNodeRec_
{
FT_LruNodeRec lru;
FT_Face face;
FTC_MruNodeRec node;
FTC_FaceID face_id;
FT_Face face;
} FTC_FaceNodeRec;
} FTC_FaceNodeRec, *FTC_FaceNode;
typedef struct FTC_SizeNodeRec_
{
FT_LruNodeRec lru;
FT_Size size;
} FTC_SizeNodeRec;
FT_CALLBACK_DEF( FT_Error )
ftc_face_node_init( FTC_FaceNode node,
FTC_FaceID face_id,
FTC_Manager manager )
{
FT_Error error;
FT_Error error;
node->face_id = face_id;
error = manager->request_face( face_id,
manager->library,
@ -79,60 +203,59 @@
if ( node->face->size )
FT_Done_Size( node->face->size );
}
return error;
}
/* helper function for ftc_face_node_done() */
FT_CALLBACK_DEF( FT_Bool )
ftc_size_node_select( FTC_SizeNode node,
FT_Face face )
{
return FT_BOOL( node->size->face == face );
}
FT_CALLBACK_DEF( void )
ftc_face_node_done( FTC_FaceNode node,
FTC_Manager manager )
{
FT_Face face = node->face;
FT_Memory memory = manager->memory;
/* 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 );
/* 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( face );
node->face = NULL;
FT_Done_Face( node->face );
node->face = NULL;
node->face_id = NULL;
FT_FREE( node );
}
FT_CALLBACK_TABLE_DEF
const FT_LruList_ClassRec ftc_face_list_class =
FT_CALLBACK_DEF( FT_Bool )
ftc_face_node_compare( FTC_FaceNode node,
FTC_FaceID face_id )
{
sizeof ( FT_LruListRec ),
(FT_LruList_InitFunc)0,
(FT_LruList_DoneFunc)0,
return FT_BOOL( node->face_id == face_id );
}
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 */
static const FTC_MruListClassRec ftc_face_list_class =
{
sizeof( FTC_FaceNodeRec),
(FTC_MruNode_CompareFunc) ftc_face_node_compare,
(FTC_MruNode_InitFunc) ftc_face_node_init,
(FTC_MruNode_ResetFunc) NULL,
(FTC_MruNode_DoneFunc) ftc_face_node_done
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_Manager_Lookup_Face( FTC_Manager manager,
FTC_FaceID face_id,
FT_Face *aface )
FTC_Manager_LookupFace( FTC_Manager manager,
FTC_FaceID face_id,
FT_Face *aface )
{
FT_Error error;
FTC_FaceNode node;
@ -146,9 +269,9 @@
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->faces,
face_id,
(FTC_MruNode*) &node );
if ( !error )
*aface = node->face;
@ -156,281 +279,6 @@
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** SIZES LRU IMPLEMENTATION *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct FTC_SizeQueryRec_
{
FT_Face face;
FT_UInt width;
FT_UInt height;
} FTC_SizeQueryRec, *FTC_SizeQuery;
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_init( FTC_SizeNode node,
FTC_SizeQuery query )
{
FT_Face face = query->face;
FT_Size size;
FT_Error error;
node->size = NULL;
error = FT_New_Size( face, &size );
if ( !error )
{
FT_Activate_Size( size );
error = FT_Set_Pixel_Sizes( query->face,
query->width,
query->height );
if ( error )
FT_Done_Size( size );
else
node->size = size;
}
return error;
}
FT_CALLBACK_DEF( void )
ftc_size_node_done( FTC_SizeNode node )
{
if ( node->size )
{
FT_Done_Size( node->size );
node->size = NULL;
}
}
FT_CALLBACK_DEF( FT_Error )
ftc_size_node_flush( FTC_SizeNode node,
FTC_SizeQuery query )
{
FT_Size size = node->size;
FT_Error error;
if ( size->face == query->face )
{
FT_Activate_Size( size );
error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
if ( error )
{
FT_Done_Size( size );
node->size = NULL;
}
}
else
{
FT_Done_Size( size );
node->size = NULL;
error = ftc_size_node_init( node, query );
}
return error;
}
FT_CALLBACK_DEF( FT_Bool )
ftc_size_node_compare( FTC_SizeNode node,
FTC_SizeQuery query )
{
FT_Size size = node->size;
return FT_BOOL( size->face == query->face &&
(FT_UInt)size->metrics.x_ppem == query->width &&
(FT_UInt)size->metrics.y_ppem == query->height );
}
FT_CALLBACK_TABLE_DEF
const FT_LruList_ClassRec ftc_size_list_class =
{
sizeof ( FT_LruListRec ),
(FT_LruList_InitFunc)0,
(FT_LruList_DoneFunc)0,
sizeof ( FTC_SizeNodeRec ),
(FT_LruNode_InitFunc) ftc_size_node_init,
(FT_LruNode_DoneFunc) ftc_size_node_done,
(FT_LruNode_FlushFunc) ftc_size_node_flush,
(FT_LruNode_CompareFunc)ftc_size_node_compare
};
/* documentation is in ftcache.h */
FT_EXPORT_DEF( FT_Error )
FTC_Manager_Lookup_Size( FTC_Manager manager,
FTC_Font font,
FT_Face *aface,
FT_Size *asize )
{
FT_Error error;
/* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
if ( aface )
*aface = 0;
if ( asize )
*asize = 0;
error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
if ( !error )
{
FTC_SizeQueryRec query;
FTC_SizeNode node;
query.face = *aface;
query.width = font->pix_width;
query.height = font->pix_height;
error = FT_LruList_Lookup( manager->sizes_list,
(FT_LruKey)&query,
(FT_LruNode*)&node );
if ( !error )
{
/* select the size as the current one for this face */
FT_Activate_Size( node->size );
if ( asize )
*asize = node->size;
}
}
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** SET TABLE MANAGEMENT *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static void
ftc_family_table_init( FTC_FamilyTable table )
{
table->count = 0;
table->size = 0;
table->entries = NULL;
table->free = FTC_FAMILY_ENTRY_NONE;
}
static void
ftc_family_table_done( FTC_FamilyTable table,
FT_Memory memory )
{
FT_FREE( table->entries );
table->free = 0;
table->count = 0;
table->size = 0;
}
FT_EXPORT_DEF( FT_Error )
ftc_family_table_alloc( FTC_FamilyTable table,
FT_Memory memory,
FTC_FamilyEntry *aentry )
{
FTC_FamilyEntry entry;
FT_Error error = 0;
/* re-allocate table size when needed */
if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
{
FT_UInt old_size = table->size;
FT_UInt new_size, idx;
if ( old_size == 0 )
new_size = 8;
else
{
new_size = old_size * 2;
/* check for (unlikely) overflow */
if ( new_size < old_size )
new_size = 65534;
}
if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
return error;
table->size = new_size;
entry = table->entries + old_size;
table->free = old_size;
for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
{
entry->link = idx + 1;
entry->index = idx;
}
entry->link = FTC_FAMILY_ENTRY_NONE;
entry->index = idx;
}
if ( table->free != FTC_FAMILY_ENTRY_NONE )
{
entry = table->entries + table->free;
table->free = entry->link;
}
else if ( table->count < table->size )
{
entry = table->entries + table->count++;
}
else
{
FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
return FTC_Err_Invalid_Argument;
}
entry->link = FTC_FAMILY_ENTRY_NONE;
table->count++;
*aentry = entry;
return error;
}
FT_EXPORT_DEF( void )
ftc_family_table_free( FTC_FamilyTable table,
FT_UInt idx )
{
/* simply add it to the linked list of free entries */
if ( idx < table->count )
{
FTC_FamilyEntry entry = table->entries + idx;
if ( entry->link != FTC_FAMILY_ENTRY_NONE )
FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
else
{
entry->link = table->free;
table->free = entry->index;
table->count--;
}
}
}
/*************************************************************************/
@ -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--;
}
}

204
src/cache/ftcmru.c vendored Normal file
View File

@ -0,0 +1,204 @@
#include <ft2build.h>
#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 */

539
src/cache/ftcsbits.c vendored
View File

@ -18,8 +18,7 @@
#include <ft2build.h>
#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;
/* 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;
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);
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 */
/* copy the bitmap into a new buffer -- ignore error */
error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
/* 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;
/* now, compute size */
if ( asize )
*asize = ABS( sbit->pitch ) * sbit->height;
} /* glyph loading successful */
} /* 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! */
}
/* 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 */

390
src/cache/ftlru.c vendored
View File

@ -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 <ft2build.h>
#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 */

6
src/cache/rules.mk vendored
View File

@ -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