From 781072441efbb671077a607b0cedc4a9d99e7fe6 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Tue, 3 Feb 2004 21:34:29 +0000 Subject: [PATCH] * src/type1/t1load.c (parse_dict): Handle `RD' and `-|' commands outside of /Subrs or /CharStrings. This can happen if there is additional code manipulating those two arrays so that FreeType doesn't recognize them properly. (T1_Open_Face): Improve an error message. Remove CR/LF on many files. --- ChangeLog | 28 +- Jamfile | 2 +- include/freetype/cache/ftccache.h | 542 ++++----- include/freetype/cache/ftcglyph.h | 594 ++++----- include/freetype/cache/ftcmru.h | 492 ++++---- src/autofit/afhints.c | 1872 ++++++++++++++--------------- src/autofit/afloader.c | 862 ++++++------- src/autofit/afloader.h | 99 +- src/autofit/afmodule.h | 33 +- src/autofit/autofit.c | 18 +- src/autohint/ahmodule.c | 2 +- src/cache/Jamfile | 2 +- src/cache/descrip.mms | 2 +- src/cache/ftcbasic.c | 2 +- src/cache/ftccmap.c | 2 +- src/cache/ftcmru.c | 2 +- src/sfnt/Jamfile | 2 +- src/type1/t1load.c | 62 +- 18 files changed, 2336 insertions(+), 2282 deletions(-) diff --git a/ChangeLog b/ChangeLog index c83999008..70d0c0b3e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-02-02 Werner Lemberg + + * src/type1/t1load.c (parse_dict): Handle `RD' and `-|' commands + outside of /Subrs or /CharStrings. This can happen if there is + additional code manipulating those two arrays so that FreeType + doesn't recognize them properly. + (T1_Open_Face): Improve an error message. + 2004-02-01 Werner Lemberg * src/type1/t1load.c (parse_charstrings): Exit immediately if @@ -9,16 +17,28 @@ * src/sfnt/Jamfile: Removing `ttcmap' from the list of sources. - * src/cache/*, include/freetype/cache/*: Fixing a bug after heavy - testing. The current sources are now `release candidates' for the - final version of the cache sub-system. + * include/freetype/cache/ftccache.h (FTC_CACHE_LOOKUP_CMP) + : Provide macro version which doesn't use inline code. + * include/freetype/cache/ftcglyph.h (FTC_GCACHE_LOOKUP_CMP) + : Ditto. + Use FTC_MRULIST_LOOKUP_CMP. + * include/freetype/cache/ftcmru.h (FTC_MRULIST_LOOKUP_CMP): New + macro. + (FTC_MRULIST_LOOKUP): Use it. + + * src/cache/Jamfile (_sources), src/cache/descrip.mms: Updated. + * src/cache/ftcbasic.c: Fix compiler warnings. + * src/cache/ftcmanag.c (FTC_Manager_LookupSize, + FTC_Manager_LookupFace) : Use FTC_MRULIST_LOOKUP_CMP. + * src/cache/ftcmru.c (FTC_MruList_Find): Fix a bug (found after + heavy testing). * Jamfile: Updating `refdoc' target, and adding `autohint' to the list of modules to build. Both the autohinter and autofitter will be built by default. But which one will be used is determined by the content of `ftmodule.h'. - * src/autofit/*: Much updates, but the code is still buggy... + * src/autofit/*: Many updates, but the code is still buggy... 2004-01-31 Werner Lemberg diff --git a/Jamfile b/Jamfile index 3f827d1c5..61583c729 100644 --- a/Jamfile +++ b/Jamfile @@ -1,4 +1,4 @@ -# FreeType 2 top Jamfile (c) 2001, 2002, 2003 David Turner +# FreeType 2 top Jamfile (c) 2001, 2002, 2003, 2004 David Turner # # The HDRMACRO is already defined in FTJam and is used to add diff --git a/include/freetype/cache/ftccache.h b/include/freetype/cache/ftccache.h index 9379d7fe6..00da7eb48 100644 --- a/include/freetype/cache/ftccache.h +++ b/include/freetype/cache/ftccache.h @@ -1,271 +1,271 @@ -/***************************************************************************/ -/* */ -/* ftccache.h */ -/* */ -/* FreeType internal cache interface (specification). */ -/* */ -/* 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. */ -/* */ -/***************************************************************************/ - - -#ifndef __FTCCACHE_H__ -#define __FTCCACHE_H__ - - -#include FT_CACHE_INTERNAL_MRU_H - -FT_BEGIN_HEADER - - /* handle to cache object */ - typedef struct FTC_CacheRec_* FTC_Cache; - - /* handle to cache class */ - typedef const struct FTC_CacheClassRec_* FTC_CacheClass; - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE NODE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* Each cache controls one or more cache nodes. Each node is part of */ - /* the global_lru list of the manager. Its `data' field however is used */ - /* as a reference count for now. */ - /* */ - /* A node can be anything, depending on the type of information held by */ - /* the cache. It can be an individual glyph image, a set of bitmaps */ - /* glyphs for a given size, some metrics, etc. */ - /* */ - /*************************************************************************/ - - /* structure size should be 20 bytes on 32-bits machines */ - typedef struct FTC_NodeRec_ - { - FTC_MruNodeRec mru; /* circular mru list pointer */ - FTC_Node link; /* used for hashing */ - FT_UInt32 hash; /* used for hashing too */ - FT_UShort cache_index; /* index of cache the node belongs to */ - FT_Short ref_count; /* reference count for this node */ - - } FTC_NodeRec; - - -#define FTC_NODE( x ) ( (FTC_Node)(x) ) -#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) - -#define FTC_NODE__NEXT(x) FTC_NODE( (x)->mru.next ) -#define FTC_NODE__PREV(x) FTC_NODE( (x)->mru.prev ) - - - /*************************************************************************/ - /* */ - /* 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. */ - /* */ - - /* reserved for manager's use */ - FT_EXPORT( void ) - ftc_node_destroy( FTC_Node node, - FTC_Manager manager ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CACHE DEFINITIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* 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_ - { - FT_UFast p; - FT_UFast mask; - FT_Long slack; - FTC_Node* buckets; - - 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; - - -#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) -#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) - - - /* default cache initialize */ - FT_EXPORT( FT_Error ) - FTC_Cache_Init( FTC_Cache cache ); - - /* 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, - FT_UInt32 hash, - FT_Pointer query, - FTC_Node *anode ); - - FT_EXPORT( FT_Error ) - FTC_Cache_NewNode( 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 final 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 ); - - -#ifdef FTC_INLINE - -#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ - FT_BEGIN_STMNT \ - FTC_Node *_bucket, *_pnode, _node; \ - FTC_Cache _cache = FTC_CACHE(cache); \ - FT_UInt32 _hash = (FT_UInt32)(hash); \ - FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ - FT_UInt _idx; \ - \ - \ - error = 0; \ - _idx = _hash & _cache->mask; \ - if ( _idx < _cache->p ) \ - _idx = _hash & (_cache->mask*2 + 1); \ - \ - _bucket = _pnode = _cache->buckets + _idx; \ - for (;;) \ - { \ - _node = *_pnode; \ - if ( _node == NULL ) \ - goto _NewNode; \ - \ - if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) ) \ - break; \ - \ - _pnode = &_node->link; \ - } \ - \ - if ( _node != *_bucket ) \ - { \ - *_pnode = _node->link; \ - _node->link = *_bucket; \ - *_bucket = _node; \ - } \ - \ - { \ - FTC_Manager _manager = _cache->manager; \ - \ - \ - if ( _node != _manager->nodes_list ) \ - FTC_MruNode_Up( (FTC_MruNode*)&_manager->nodes_list, \ - (FTC_MruNode)_node ); \ - } \ - goto _Ok; \ - \ - _NewNode: \ - error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ - \ - _Ok: \ - *(FTC_Node*)&(node) = _node; \ - FT_END_STMNT - -#else /* !FTC_INLINE */ - -#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ - FT_BEGIN_STMNT \ - error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, \ - (FTC_Node*)&(node) ); \ - FT_END_STMNT - -#endif /* !FTC_INLINE */ - - /* */ - -FT_END_HEADER - - -#endif /* __FTCCACHE_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftccache.h */ +/* */ +/* FreeType internal cache interface (specification). */ +/* */ +/* Copyright 2000-2001, 2002, 2003, 2004 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. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTCCACHE_H__ +#define __FTCCACHE_H__ + + +#include FT_CACHE_INTERNAL_MRU_H + +FT_BEGIN_HEADER + + /* handle to cache object */ + typedef struct FTC_CacheRec_* FTC_Cache; + + /* handle to cache class */ + typedef const struct FTC_CacheClassRec_* FTC_CacheClass; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE NODE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* Each cache controls one or more cache nodes. Each node is part of */ + /* the global_lru list of the manager. Its `data' field however is used */ + /* as a reference count for now. */ + /* */ + /* A node can be anything, depending on the type of information held by */ + /* the cache. It can be an individual glyph image, a set of bitmaps */ + /* glyphs for a given size, some metrics, etc. */ + /* */ + /*************************************************************************/ + + /* structure size should be 20 bytes on 32-bits machines */ + typedef struct FTC_NodeRec_ + { + FTC_MruNodeRec mru; /* circular mru list pointer */ + FTC_Node link; /* used for hashing */ + FT_UInt32 hash; /* used for hashing too */ + FT_UShort cache_index; /* index of cache the node belongs to */ + FT_Short ref_count; /* reference count for this node */ + + } FTC_NodeRec; + + +#define FTC_NODE( x ) ( (FTC_Node)(x) ) +#define FTC_NODE_P( x ) ( (FTC_Node*)(x) ) + +#define FTC_NODE__NEXT(x) FTC_NODE( (x)->mru.next ) +#define FTC_NODE__PREV(x) FTC_NODE( (x)->mru.prev ) + + + /*************************************************************************/ + /* */ + /* 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. */ + /* */ + + /* reserved for manager's use */ + FT_EXPORT( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CACHE DEFINITIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* 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_ + { + FT_UFast p; + FT_UFast mask; + FT_Long slack; + FTC_Node* buckets; + + 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; + + +#define FTC_CACHE( x ) ( (FTC_Cache)(x) ) +#define FTC_CACHE_P( x ) ( (FTC_Cache*)(x) ) + + + /* default cache initialize */ + FT_EXPORT( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ); + + /* 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, + FT_UInt32 hash, + FT_Pointer query, + FTC_Node *anode ); + + FT_EXPORT( FT_Error ) + FTC_Cache_NewNode( 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 final 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 ); + + +#ifdef FTC_INLINE + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_Node *_bucket, *_pnode, _node; \ + FTC_Cache _cache = FTC_CACHE(cache); \ + FT_UInt32 _hash = (FT_UInt32)(hash); \ + FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ + FT_UInt _idx; \ + \ + \ + error = 0; \ + _idx = _hash & _cache->mask; \ + if ( _idx < _cache->p ) \ + _idx = _hash & (_cache->mask*2 + 1); \ + \ + _bucket = _pnode = _cache->buckets + _idx; \ + for (;;) \ + { \ + _node = *_pnode; \ + if ( _node == NULL ) \ + goto _NewNode; \ + \ + if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) ) \ + break; \ + \ + _pnode = &_node->link; \ + } \ + \ + if ( _node != *_bucket ) \ + { \ + *_pnode = _node->link; \ + _node->link = *_bucket; \ + *_bucket = _node; \ + } \ + \ + { \ + FTC_Manager _manager = _cache->manager; \ + \ + \ + if ( _node != _manager->nodes_list ) \ + FTC_MruNode_Up( (FTC_MruNode*)&_manager->nodes_list, \ + (FTC_MruNode)_node ); \ + } \ + goto _Ok; \ + \ + _NewNode: \ + error = FTC_Cache_NewNode( _cache, _hash, query, &_node ); \ + \ + _Ok: \ + *(FTC_Node*)&(node) = _node; \ + FT_END_STMNT + +#else /* !FTC_INLINE */ + +#define FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ) \ + FT_BEGIN_STMNT \ + error = FTC_Cache_Lookup( FTC_CACHE(cache), hash, query, \ + (FTC_Node*)&(node) ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + /* */ + +FT_END_HEADER + + +#endif /* __FTCCACHE_H__ */ + + +/* END */ diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h index 00f9cee55..1c958fbee 100644 --- a/include/freetype/cache/ftcglyph.h +++ b/include/freetype/cache/ftcglyph.h @@ -1,297 +1,297 @@ -/***************************************************************************/ -/* */ -/* ftcglyph.h */ -/* */ -/* FreeType abstract glyph 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. */ -/* */ -/***************************************************************************/ - - - /* - * - * 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 into 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 an FTC_Node with two additional 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 synthesis, 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 additional - * optimizations. - * - * A typical FTC_GCache implementation must provide at least the - * following: - * - * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: - * 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: - * 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. - * - * - Constant structures for a FTC_GNodeClass. - * - * - MyCacheNew() can be implemented easily as a call to the convenience - * function FTC_GCache_New. - * - * - 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. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /********* *********/ - /********* WARNING, THIS IS BETA CODE. *********/ - /********* *********/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - -#ifndef __FTCGLYPH_H__ -#define __FTCGLYPH_H__ - - -#include -#include FT_CACHE_INTERNAL_MANAGER_H - - -FT_BEGIN_HEADER - - - /* - * We can group glyphs into `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_MruNodeRec mrunode; - FT_UInt num_nodes; /* current number of nodes in this family */ - FTC_Cache cache; - FTC_MruListClass clazz; - - } FTC_FamilyRec, *FTC_Family; - -#define FTC_FAMILY(x) ( (FTC_Family)(x) ) -#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) - - - typedef struct FTC_GNodeRec_ - { - FTC_NodeRec node; - FTC_Family family; - FT_UInt gindex; - - } FTC_GNodeRec, *FTC_GNode; - -#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) -#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) - - - typedef struct FTC_GQueryRec_ - { - FT_UInt gindex; - FTC_Family family; - - } FTC_GQueryRec, *FTC_GQuery; - -#define FTC_GQUERY( x ) ( (FTC_GQuery)(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 derived FTC_Node_InitFunc routines */ - FT_EXPORT( void ) - 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_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_GNode_Done( FTC_GNode node, - FTC_Cache cache ); - - - FT_EXPORT( void ) - FTC_Family_Init( FTC_Family family, - FTC_Cache cache ); - - 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_GCache_Init( FTC_GCache cache ); - - - /* can be used as @FTC_Cache_DoneFunc */ - FT_EXPORT( void ) - 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 ) -#define FTC_CACHE__FAMILY_CLASS( x ) \ - ((FTC_MruListClass) FTC_CACHE__GCACHE_CLASS(x)->family_class) - - - /* convenience function; use it 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 ); - - -#ifdef FTC_INLINE - -#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ - gindex, query, node, error ) \ - FT_BEGIN_STMNT \ - FTC_GCache _gcache = FTC_GCACHE( cache ); \ - FTC_GQuery _gquery = (FTC_GQuery)( query ); \ - FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ - \ - \ - _gquery->gindex = (gindex); \ - \ - FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ - _gquery->family, error ); \ - if ( !error ) \ - { \ - FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ - } \ - FT_END_STMNT - /* */ - -#else /* !FTC_INLINE */ - -#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ - gindex, query, node, error ) \ - FT_BEGIN_STMNT \ - error = FTC_GCache_Lookup( FTC_GCACHE(cache), hash, gindex, FTC_GQUERY(query), \ - (FTC_Node*) &(node) ); \ - FT_END_STMNT - -#endif /* !FTC_INLINE */ - - -FT_END_HEADER - - -#endif /* __FTCGLYPH_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftcglyph.h */ +/* */ +/* FreeType abstract glyph cache (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2004 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. */ +/* */ +/***************************************************************************/ + + + /* + * + * 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 into 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 an FTC_Node with two additional 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 synthesis, 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 additional + * optimizations. + * + * A typical FTC_GCache implementation must provide at least the + * following: + * + * - FTC_GNode sub-class, e.g. MyNode, with relevant methods: + * 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: + * 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. + * + * - Constant structures for a FTC_GNodeClass. + * + * - MyCacheNew() can be implemented easily as a call to the convenience + * function FTC_GCache_New. + * + * - 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. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /********* *********/ + /********* WARNING, THIS IS BETA CODE. *********/ + /********* *********/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + +#ifndef __FTCGLYPH_H__ +#define __FTCGLYPH_H__ + + +#include +#include FT_CACHE_INTERNAL_MANAGER_H + + +FT_BEGIN_HEADER + + + /* + * We can group glyphs into `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_MruNodeRec mrunode; + FT_UInt num_nodes; /* current number of nodes in this family */ + FTC_Cache cache; + FTC_MruListClass clazz; + + } FTC_FamilyRec, *FTC_Family; + +#define FTC_FAMILY(x) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) + + + typedef struct FTC_GNodeRec_ + { + FTC_NodeRec node; + FTC_Family family; + FT_UInt gindex; + + } FTC_GNodeRec, *FTC_GNode; + +#define FTC_GNODE( x ) ( (FTC_GNode)(x) ) +#define FTC_GNODE_P( x ) ( (FTC_GNode*)(x) ) + + + typedef struct FTC_GQueryRec_ + { + FT_UInt gindex; + FTC_Family family; + + } FTC_GQueryRec, *FTC_GQuery; + +#define FTC_GQUERY( x ) ( (FTC_GQuery)(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 derived FTC_Node_InitFunc routines */ + FT_EXPORT( void ) + 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_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_GNode_Done( FTC_GNode node, + FTC_Cache cache ); + + + FT_EXPORT( void ) + FTC_Family_Init( FTC_Family family, + FTC_Cache cache ); + + 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_GCache_Init( FTC_GCache cache ); + + + /* can be used as @FTC_Cache_DoneFunc */ + FT_EXPORT( void ) + 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 ) +#define FTC_CACHE__FAMILY_CLASS( x ) \ + ((FTC_MruListClass) FTC_CACHE__GCACHE_CLASS(x)->family_class) + + + /* convenience function; use it 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 ); + + +#ifdef FTC_INLINE + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + FTC_GCache _gcache = FTC_GCACHE( cache ); \ + FTC_GQuery _gquery = (FTC_GQuery)( query ); \ + FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \ + \ + \ + _gquery->gindex = (gindex); \ + \ + FTC_MRULIST_LOOKUP_CMP( &_gcache->families, _gquery, _fcompare, \ + _gquery->family, error ); \ + if ( !error ) \ + { \ + FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \ + } \ + FT_END_STMNT + /* */ + +#else /* !FTC_INLINE */ + +#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \ + gindex, query, node, error ) \ + FT_BEGIN_STMNT \ + error = FTC_GCache_Lookup( FTC_GCACHE(cache), hash, gindex, FTC_GQUERY(query), \ + (FTC_Node*) &(node) ); \ + FT_END_STMNT + +#endif /* !FTC_INLINE */ + + +FT_END_HEADER + + +#endif /* __FTCGLYPH_H__ */ + + +/* END */ diff --git a/include/freetype/cache/ftcmru.h b/include/freetype/cache/ftcmru.h index d2bac3a87..9556f58e7 100644 --- a/include/freetype/cache/ftcmru.h +++ b/include/freetype/cache/ftcmru.h @@ -1,246 +1,246 @@ -/***************************************************************************/ -/* */ -/* ftcmru.h */ -/* */ -/* Simple MRU list-cache (specification). */ -/* */ -/* Copyright 2000-2001, 2003 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* An MRU is a list that cannot hold more than a certain number of */ - /* elements (`max_elements'). All elements in the list are sorted in */ - /* least-recently-used order, i.e., the `oldest' element is at the tail */ - /* of the list. */ - /* */ - /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ - /* the list is searched for an element with the corresponding key. If */ - /* it is found, the element is moved to the head of the list and is */ - /* returned. */ - /* */ - /* If no corresponding element is found, the lookup routine will try to */ - /* obtain a new element with the relevant key. If the list is already */ - /* full, the oldest element from the list is discarded and replaced by a */ - /* new one; a new element is added to the list otherwise. */ - /* */ - /* Note that it is possible to pre-allocate the element list nodes. */ - /* This is handy if `max_elements' is sufficiently small, as it saves */ - /* allocations/releases during the lookup process. */ - /* */ - /*************************************************************************/ - - -#ifndef __FTCMRU_H__ -#define __FTCMRU_H__ - - -#include -#include FT_FREETYPE_H - -#ifdef FREETYPE_H -#error "freetype.h of FreeType 1 has been loaded!" -#error "Please fix the directory search order for header files" -#error "so that freetype.h of FreeType 2 is found first." -#endif - -#define xxFT_DEBUG_ERROR -#define FTC_INLINE - -FT_BEGIN_HEADER - - typedef struct FTC_MruNodeRec_* FTC_MruNode; - - typedef struct FTC_MruNodeRec_ - { - FTC_MruNode next; - FTC_MruNode prev; - - } FTC_MruNodeRec; - - - FT_EXPORT( void ) - FTC_MruNode_Prepend( FTC_MruNode *plist, - FTC_MruNode node ); - - FT_EXPORT( void ) - FTC_MruNode_Up( FTC_MruNode *plist, - FTC_MruNode node ); - - FT_EXPORT( void ) - FTC_MruNode_Remove( FTC_MruNode *plist, - FTC_MruNode node ); - - - typedef struct FTC_MruListRec_* FTC_MruList; - - typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; - - - 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( FTC_MruNode ) - FTC_MruList_Find( FTC_MruList list, - FT_Pointer key ); - - FT_EXPORT( FT_Error ) - FTC_MruList_New( FTC_MruList list, - FT_Pointer key, - FTC_MruNode *anode ); - - 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 selection, - FT_Pointer key ); - - -#ifdef FTC_INLINE - -#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \ - FT_BEGIN_STMNT \ - FTC_MruNode* _pfirst = &(list)->nodes; \ - FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \ - FTC_MruNode _first, _node; \ - \ - \ - error = 0; \ - _first = *(_pfirst); \ - _node = NULL; \ - \ - if ( _first ) \ - { \ - _node = _first; \ - do \ - { \ - if ( _compare( _node, (key) ) ) \ - { \ - if ( _node != _first ) \ - FTC_MruNode_Up( _pfirst, _node ); \ - \ - *(FTC_MruNode*)&(node) = _node; \ - goto _MruOk; \ - } \ - _node = _node->next; \ - \ - } while ( _node != _first) ; \ - } \ - \ - error = FTC_MruList_New( (list), (key), (FTC_MruNode*)&(node) ); \ - _MruOk: \ - ; \ - FT_END_STMNT - -#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ - FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error ) - -#else /* !FTC_INLINE */ - -#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ - error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) - -#endif /* !FTC_INLINE */ - - -#define FTC_MRULIST_LOOP( list, node ) \ - FT_BEGIN_STMNT \ - FTC_MruNode _first = (list)->nodes; \ - \ - \ - if ( _first ) \ - { \ - FTC_MruNode _node = _first; \ - \ - \ - do \ - { \ - *(FTC_MruNode*)&(node) = _node; - - -#define FTC_MRULIST_LOOP_END() \ - _node = _node->next; \ - \ - } while ( _node != _first ); \ - } \ - FT_END_STMNT - - /* */ - -FT_END_HEADER - - -#endif /* __FTCMRU_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftcmru.h */ +/* */ +/* Simple MRU list-cache (specification). */ +/* */ +/* Copyright 2000-2001, 2003, 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* An MRU is a list that cannot hold more than a certain number of */ + /* elements (`max_elements'). All elements in the list are sorted in */ + /* least-recently-used order, i.e., the `oldest' element is at the tail */ + /* of the list. */ + /* */ + /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */ + /* the list is searched for an element with the corresponding key. If */ + /* it is found, the element is moved to the head of the list and is */ + /* returned. */ + /* */ + /* If no corresponding element is found, the lookup routine will try to */ + /* obtain a new element with the relevant key. If the list is already */ + /* full, the oldest element from the list is discarded and replaced by a */ + /* new one; a new element is added to the list otherwise. */ + /* */ + /* Note that it is possible to pre-allocate the element list nodes. */ + /* This is handy if `max_elements' is sufficiently small, as it saves */ + /* allocations/releases during the lookup process. */ + /* */ + /*************************************************************************/ + + +#ifndef __FTCMRU_H__ +#define __FTCMRU_H__ + + +#include +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + +#define xxFT_DEBUG_ERROR +#define FTC_INLINE + +FT_BEGIN_HEADER + + typedef struct FTC_MruNodeRec_* FTC_MruNode; + + typedef struct FTC_MruNodeRec_ + { + FTC_MruNode next; + FTC_MruNode prev; + + } FTC_MruNodeRec; + + + FT_EXPORT( void ) + FTC_MruNode_Prepend( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_EXPORT( void ) + FTC_MruNode_Up( FTC_MruNode *plist, + FTC_MruNode node ); + + FT_EXPORT( void ) + FTC_MruNode_Remove( FTC_MruNode *plist, + FTC_MruNode node ); + + + typedef struct FTC_MruListRec_* FTC_MruList; + + typedef struct FTC_MruListClassRec_ const * FTC_MruListClass; + + + 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( FTC_MruNode ) + FTC_MruList_Find( FTC_MruList list, + FT_Pointer key ); + + FT_EXPORT( FT_Error ) + FTC_MruList_New( FTC_MruList list, + FT_Pointer key, + FTC_MruNode *anode ); + + 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 selection, + FT_Pointer key ); + + +#ifdef FTC_INLINE + +#define FTC_MRULIST_LOOKUP_CMP( list, key, compare, node, error ) \ + FT_BEGIN_STMNT \ + FTC_MruNode* _pfirst = &(list)->nodes; \ + FTC_MruNode_CompareFunc _compare = (FTC_MruNode_CompareFunc)(compare); \ + FTC_MruNode _first, _node; \ + \ + \ + error = 0; \ + _first = *(_pfirst); \ + _node = NULL; \ + \ + if ( _first ) \ + { \ + _node = _first; \ + do \ + { \ + if ( _compare( _node, (key) ) ) \ + { \ + if ( _node != _first ) \ + FTC_MruNode_Up( _pfirst, _node ); \ + \ + *(FTC_MruNode*)&(node) = _node; \ + goto _MruOk; \ + } \ + _node = _node->next; \ + \ + } while ( _node != _first) ; \ + } \ + \ + error = FTC_MruList_New( (list), (key), (FTC_MruNode*)&(node) ); \ + _MruOk: \ + ; \ + FT_END_STMNT + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + FTC_MRULIST_LOOKUP_CMP( list, key, (list)->clazz.node_compare, node, error ) + +#else /* !FTC_INLINE */ + +#define FTC_MRULIST_LOOKUP( list, key, node, error ) \ + error = FTC_MruList_Lookup( (list), (key), (FTC_MruNode*)&(node) ) + +#endif /* !FTC_INLINE */ + + +#define FTC_MRULIST_LOOP( list, node ) \ + FT_BEGIN_STMNT \ + FTC_MruNode _first = (list)->nodes; \ + \ + \ + if ( _first ) \ + { \ + FTC_MruNode _node = _first; \ + \ + \ + do \ + { \ + *(FTC_MruNode*)&(node) = _node; + + +#define FTC_MRULIST_LOOP_END() \ + _node = _node->next; \ + \ + } while ( _node != _first ); \ + } \ + FT_END_STMNT + + /* */ + +FT_END_HEADER + + +#endif /* __FTCMRU_H__ */ + + +/* END */ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index ef6410d47..4cc55ebef 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -1,938 +1,934 @@ -#include "afhints.h" - -#ifdef AF_DEBUG - -#include - - void - af_glyph_hints_dump_edges( AF_GlyphHints hints ) - { - AF_Edge edges; - AF_Edge edge_limit; - AF_Segment segments; - FT_Int dimension; - - - edges = hints->horz_edges; - edge_limit = edges + hints->num_hedges; - segments = hints->horz_segments; - - for ( dimension = 1; dimension >= 0; dimension-- ) - { - AF_Edge edge; - - - printf ( "Table of %s edges:\n", - !dimension ? "vertical" : "horizontal" ); - printf ( " [ index | pos | dir | link |" - " serif | blue | opos | pos ]\n" ); - - for ( edge = edges; edge < edge_limit; edge++ ) - { - printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", - edge - edges, - (int)edge->fpos, - edge->dir == AF_DIR_UP - ? "up" - : ( edge->dir == AF_DIR_DOWN - ? "down" - : ( edge->dir == AF_DIR_LEFT - ? "left" - : ( edge->dir == AF_DIR_RIGHT - ? "right" - : "none" ) ) ), - edge->link ? ( edge->link - edges ) : -1, - edge->serif ? ( edge->serif - edges ) : -1, - edge->blue_edge ? 'y' : 'n', - edge->opos / 64.0, - edge->pos / 64.0 ); - } - - edges = hints->vert_edges; - edge_limit = edges + hints->num_vedges; - segments = hints->vert_segments; - } - } - - - /* A function used to dump the array of linked segments */ - void - af_glyph_hints_dump_segments( AF_GlyphHints hints ) - { - AF_Segment segments; - AF_Segment segment_limit; - AF_Point points; - FT_Int dimension; - - - points = hints->points; - segments = hints->horz_segments; - segment_limit = segments + hints->num_hsegments; - - for ( dimension = 1; dimension >= 0; dimension-- ) - { - AF_Segment seg; - - - printf ( "Table of %s segments:\n", - !dimension ? "vertical" : "horizontal" ); - printf ( " [ index | pos | dir | link | serif |" - " numl | first | start ]\n" ); - - for ( seg = segments; seg < segment_limit; seg++ ) - { - printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n", - seg - segments, - (int)seg->pos, - seg->dir == AF_DIR_UP - ? "up" - : ( seg->dir == AF_DIR_DOWN - ? "down" - : ( seg->dir == AF_DIR_LEFT - ? "left" - : ( seg->dir == AF_DIR_RIGHT - ? "right" - : "none" ) ) ), - seg->link ? ( seg->link - segments ) : -1, - seg->serif ? ( seg->serif - segments ) : -1, - (int)seg->num_linked, - seg->first - points, - seg->last - points ); - } - - segments = hints->vert_segments; - segment_limit = segments + hints->num_vsegments; - } - } - -#endif /* AF_DEBUG */ - - - /* compute the direction value of a given vector */ - FT_LOCAL_DEF( AF_Direction ) - af_direction_compute( FT_Pos dx, - FT_Pos dy ) - { - AF_Direction dir; - FT_Pos ax = ABS( dx ); - FT_Pos ay = ABS( dy ); - - - dir = AF_DIR_NONE; - - /* atan(1/12) == 4.7 degrees */ - - /* test for vertical direction */ - if ( ax * 12 < ay ) - { - dir = dy > 0 ? AF_DIR_UP : AF_DIR_DOWN; - } - /* test for horizontal direction */ - else if ( ay * 12 < ax ) - { - dir = dx > 0 ? AF_DIR_RIGHT : AF_DIR_LEFT; - } - - return dir; - } - - - /* compute all inflex points in a given glyph */ - static void - af_glyph_hints_compute_inflections( AF_GlyphHints hints ) - { - AF_Point* contour = hints->contours; - AF_Point* contour_limit = contour + hints->num_contours; - - - /* do each contour separately */ - for ( ; contour < contour_limit; contour++ ) - { - AF_Point point = contour[0]; - AF_Point first = point; - AF_Point start = point; - AF_Point end = point; - AF_Point before; - AF_Point after; - AF_Angle angle_in, angle_seg, angle_out; - AF_Angle diff_in, diff_out; - FT_Int finished = 0; - - - /* compute first segment in contour */ - first = point; - - start = end = first; - do - { - end = end->next; - if ( end == first ) - goto Skip; - - } while ( end->fx == first->fx && end->fy == first->fy ); - - angle_seg = af_angle_atan( end->fx - start->fx, - end->fy - start->fy ); - - /* extend the segment start whenever possible */ - before = start; - do - { - do - { - start = before; - before = before->prev; - if ( before == first ) - goto Skip; - - } while ( before->fx == start->fx && before->fy == start->fy ); - - angle_in = af_angle_atan( start->fx - before->fx, - start->fy - before->fy ); - - } while ( angle_in == angle_seg ); - - first = start; - diff_in = af_angle_diff( angle_in, angle_seg ); - - /* now, process all segments in the contour */ - do - { - /* first, extend current segment's end whenever possible */ - after = end; - do - { - do - { - end = after; - after = after->next; - if ( after == first ) - finished = 1; - - } while ( end->fx == after->fx && end->fy == after->fy ); - - angle_out = af_angle_atan( after->fx - end->fx, - after->fy - end->fy ); - - } while ( angle_out == angle_seg ); - - diff_out = af_angle_diff( angle_seg, angle_out ); - - if ( ( diff_in ^ diff_out ) < 0 ) - { - /* diff_in and diff_out have different signs, we have */ - /* inflection points here... */ - do - { - start->flags |= AF_FLAG_INFLECTION; - start = start->next; - - } while ( start != end ); - - start->flags |= AF_FLAG_INFLECTION; - } - - start = end; - end = after; - angle_seg = angle_out; - diff_in = diff_out; - - } while ( !finished ); - - Skip: - ; - } - } - - - - FT_LOCAL_DEF( void ) - af_glyph_hints_init( AF_GlyphHints hints, - FT_Memory memory ) - { - FT_ZERO( hints ); - hints->memory = memory; - } - - - - FT_LOCAL_DEF( void ) - af_glyph_hints_done( AF_GlyphHints hints ) - { - if ( hints && hints->memory ) - { - FT_Memory memory = hints->memory; - AF_Dimension dim; - - /* note that we don't need to free the segment and edge - * buffers, since they're really within the hints->points array - */ - for ( dim = 0; dim < 2; dim++ ) - { - AF_AxisHints axis = &hints->axis[ dim ]; - - axis->num_segments = 0; - axis->num_edges = 0; - axis->segments = NULL; - axis->edges = NULL; - } - - FT_FREE( hints->contours ); - hints->max_contours = 0; - hints->num_contours = 0; - - FT_FREE( hints->points ); - hints->num_points = 0; - hints->max_points = 0; - - hints->memory = NULL; - } - } - - - - FT_LOCAL_DEF( FT_Error ) - af_glyph_hints_reset( AF_GlyphHints hints, - AF_Scaler scaler, - FT_Outline* outline ) - { - FT_Error error = FT_Err_Ok; - AF_Point points; - FT_UInt old_max, new_max; - FT_Fixed x_scale = scaler->x_scale; - FT_Fixed y_scale = scaler->y_scale; - FT_Pos x_delta = scaler->x_delta; - FT_Pos y_delta = scaler->y_delta; - FT_Memory memory = hints->memory; - - hints->scaler_flags = scaler->flags; - hints->other_flags = 0; - - hints->num_points = 0; - hints->num_contours = 0; - - hints->axis[0].num_segments = 0; - hints->axis[0].num_edges = 0; - hints->axis[1].num_segments = 0; - hints->axis[1].num_edges = 0; - - /* first of all, reallocate the contours array when necessary - */ - new_max = (FT_UInt) outline->n_contours; - old_max = hints->max_contours; - if ( new_max > old_max ) - { - new_max = (new_max + 3) & ~3; - - if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) - goto Exit; - - hints->max_contours = new_max; - } - - /* then, reallocate the points, segments & edges arrays if needed -- - * note that we reserved two additional point positions, used to - * hint metrics appropriately - */ - new_max = (FT_UInt)( outline->n_points + 2 ); - old_max = hints->max_points; - if ( new_max > old_max ) - { - FT_Byte* items; - FT_ULong off1, off2, off3; - - /* we store in a single buffer the following arrays: - * - * - an array of N AF_PointRec items - * - an array of 2*N AF_SegmentRec items - * - an array of 2*N AF_EdgeRec items - * - */ - - new_max = ( new_max + 2 + 7 ) & ~7; - -#undef OFF_INCREMENT -#define OFF_INCREMENT( _off, _type, _count ) \ - ( FT_PAD_CEIL( _off, sizeof(_type) ) + (_count)*sizeof(_type)) - - off1 = OFF_INCREMENT( 0, AF_PointRec, new_max ); - off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max ); - off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 ); - - FT_FREE( hints->points ); - - if ( FT_ALLOC( items, off3 ) ) - { - hints->max_points = 0; - hints->axis[0].segments = NULL; - hints->axis[0].edges = NULL; - hints->axis[1].segments = NULL; - hints->axis[1].edges = NULL; - goto Exit; - } - - /* readjust some pointers - */ - hints->max_points = new_max; - hints->points = (AF_Point) items; - - hints->axis[0].segments = (AF_Segment)( items + off1 ); - hints->axis[1].segments = hints->axis[0].segments + new_max; - - hints->axis[0].edges = (AF_Edge) ( items + off2 ); - hints->axis[1].edges = hints->axis[0].edges + new_max; - } - - hints->num_points = outline->n_points; - hints->num_contours = outline->n_contours; - - - /* We can't rely on the value of `FT_Outline.flags' to know the fill */ - /* direction used for a glyph, given that some fonts are broken (e.g. */ - /* the Arphic ones). We thus recompute it each time we need to. */ - /* */ - hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP; - hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT; - - if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) - { - hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN; - hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT; - } - - 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; - - { - AF_Point point; - AF_Point point_limit = points + hints->num_points; - - - /* compute coordinates & bezier flags */ - { - FT_Vector* vec = outline->points; - char* tag = outline->tags; - - - for ( point = points; point < point_limit; point++, vec++, tag++ ) - { - point->fx = vec->x; - point->fy = vec->y; - point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; - point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; - - switch ( FT_CURVE_TAG( *tag ) ) - { - case FT_CURVE_TAG_CONIC: - point->flags = AF_FLAG_CONIC; - break; - case FT_CURVE_TAG_CUBIC: - point->flags = AF_FLAG_CUBIC; - break; - default: - point->flags = 0; - ; - } - } - } - - /* compute `next' and `prev' */ - { - FT_Int contour_index; - AF_Point prev; - AF_Point first; - AF_Point end; - - - contour_index = 0; - - first = points; - end = points + outline->contours[0]; - prev = end; - - for ( point = points; point < point_limit; point++ ) - { - point->prev = prev; - if ( point < end ) - { - point->next = point + 1; - prev = point; - } - else - { - point->next = first; - contour_index++; - if ( point + 1 < point_limit ) - { - end = points + outline->contours[contour_index]; - first = point + 1; - prev = end; - } - } - } - } - - /* set-up the contours array */ - { - AF_Point* contour = hints->contours; - AF_Point* contour_limit = contour + hints->num_contours; - short* end = outline->contours; - short idx = 0; - - - for ( ; contour < contour_limit; contour++, end++ ) - { - contour[0] = points + idx; - idx = (short)( end[0] + 1 ); - } - } - - /* compute directions of in & out vectors */ - { - for ( point = points; point < point_limit; point++ ) - { - AF_Point prev; - AF_Point next; - FT_Pos in_x, in_y, out_x, out_y; - - - prev = point->prev; - in_x = point->fx - prev->fx; - in_y = point->fy - prev->fy; - - point->in_dir = af_direction_compute( in_x, in_y ); - - next = point->next; - out_x = next->fx - point->fx; - out_y = next->fy - point->fy; - - point->out_dir = af_direction_compute( out_x, out_y ); - - if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) - { - Is_Weak_Point: - point->flags |= AF_FLAG_WEAK_INTERPOLATION; - } - else if ( point->out_dir == point->in_dir ) - { - AF_Angle angle_in, angle_out, delta; - - - if ( point->out_dir != AF_DIR_NONE ) - goto Is_Weak_Point; - - angle_in = af_angle_atan( in_x, in_y ); - angle_out = af_angle_atan( out_x, out_y ); - delta = af_angle_diff( angle_in, angle_out ); - - if ( delta < 2 && delta > -2 ) - goto Is_Weak_Point; - } - else if ( point->in_dir == -point->out_dir ) - goto Is_Weak_Point; - } - } - } - - /* compute inflection points - */ - af_glyph_hints_compute_inflections( hints ); - - Exit: - return error; - } - - - - - /* - * - * E D G E P O I N T G R I D - F I T T I N G - * - */ - - - FT_LOCAL_DEF( void ) - af_glyph_hints_align_edge_points( AF_GlyphHints hints, - AF_Dimension dim ) - { - AF_AxisHints axis = & hints->axis[ dim ]; - AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; - AF_Edge edge; - - for ( edge = edges; edge < edge_limit; edge++ ) - { - /* move the points of each segment */ - /* in each edge to the edge's position */ - AF_Segment seg = edge->first; - - - do - { - AF_Point point = seg->first; - - - for (;;) - { - if ( dim == AF_DIMENSION_HORZ ) - { - point->x = edge->pos; - point->flags |= AF_FLAG_TOUCH_X; - } - else - { - point->y = edge->pos; - point->flags |= AF_FLAG_TOUCH_Y; - } - - if ( point == seg->last ) - break; - - point = point->next; - } - - seg = seg->edge_next; - - } while ( seg != edge->first ); - } - } - - - /* - * - * S T R O N G P O I N T I N T E R P O L A T I O N - * - */ - - - /* hint the strong points -- this is equivalent to the TrueType `IP' */ - /* hinting instruction */ - FT_LOCAL_DEF( void ) - af_glyph_hints_align_strong_points( AF_GlyphHints hints, - AF_Dimension dim ) - { - AF_Point points = hints->points; - AF_Point point_limit = points + hints->num_points; - AF_AxisHints axis = &hints->axis[dim]; - AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; - AF_Flags touch_flag; - - - if ( dim == AF_DIMENSION_HORZ ) - touch_flag = AF_FLAG_TOUCH_X; - else - touch_flag = AF_FLAG_TOUCH_Y; - - if ( edges < edge_limit ) - { - AF_Point point; - AF_Edge edge; - - for ( point = points; point < point_limit; point++ ) - { - FT_Pos u, ou, fu; /* point position */ - FT_Pos delta; - - - if ( point->flags & touch_flag ) - continue; - - /* if this point is candidate to weak interpolation, we will */ - /* interpolate it after all strong points have been processed */ - if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && - !( point->flags & AF_FLAG_INFLECTION ) ) - continue; - - if ( dim == AF_DIMENSION_VERT ) - { - u = point->fy; - ou = point->oy; - } - else - { - u = point->fx; - ou = point->ox; - } - - fu = u; - - /* is the point before the first edge? */ - edge = edges; - delta = edge->fpos - u; - if ( delta >= 0 ) - { - u = edge->pos - ( edge->opos - ou ); - goto Store_Point; - } - - /* is the point after the last edge? */ - edge = edge_limit - 1; - delta = u - edge->fpos; - if ( delta >= 0 ) - { - u = edge->pos + ( ou - edge->opos ); - goto Store_Point; - } - - { - FT_UInt min, max, mid; - FT_Pos fpos; - - - /* find enclosing edges */ - min = 0; - max = edge_limit - edges; - - while ( min < max ) - { - mid = ( max + min ) >> 1; - edge = edges + mid; - fpos = edge->fpos; - - if ( u < fpos ) - max = mid; - else if ( u > fpos ) - min = mid + 1; - else - { - /* we are on the edge */ - u = edge->pos; - goto Store_Point; - } - } - - { - AF_Edge before = edges + min - 1; - AF_Edge after = edges + min + 0; - - - /* assert( before && after && before != after ) */ - if ( before->scale == 0 ) - before->scale = FT_DivFix( after->pos - before->pos, - after->fpos - before->fpos ); - - u = before->pos + FT_MulFix( fu - before->fpos, - before->scale ); - } - } - - - Store_Point: - - /* save the point position */ - if ( dim == AF_DIMENSION_HORZ ) - point->x = u; - else - point->y = u; - - point->flags |= touch_flag; - } - } - } - - - /* - * - * W E A K P O I N T I N T E R P O L A T I O N - * - */ - - static void - af_iup_shift( AF_Point p1, - AF_Point p2, - AF_Point ref ) - { - AF_Point p; - FT_Pos delta = ref->u - ref->v; - - - for ( p = p1; p < ref; p++ ) - p->u = p->v + delta; - - for ( p = ref + 1; p <= p2; p++ ) - p->u = p->v + delta; - } - - - static void - af_iup_interp( AF_Point p1, - AF_Point p2, - AF_Point ref1, - AF_Point ref2 ) - { - AF_Point p; - FT_Pos u; - FT_Pos v1 = ref1->v; - FT_Pos v2 = ref2->v; - FT_Pos d1 = ref1->u - v1; - FT_Pos d2 = ref2->u - v2; - - - if ( p1 > p2 ) - return; - - if ( v1 == v2 ) - { - for ( p = p1; p <= p2; p++ ) - { - u = p->v; - - if ( u <= v1 ) - u += d1; - else - u += d2; - - p->u = u; - } - return; - } - - if ( v1 < v2 ) - { - for ( p = p1; p <= p2; p++ ) - { - u = p->v; - - if ( u <= v1 ) - u += d1; - else if ( u >= v2 ) - u += d2; - else - u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); - - p->u = u; - } - } - else - { - for ( p = p1; p <= p2; p++ ) - { - u = p->v; - - if ( u <= v2 ) - u += d2; - else if ( u >= v1 ) - u += d1; - else - u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); - - p->u = u; - } - } - } - - - FT_LOCAL_DEF( void ) - af_glyph_hints_align_weak_points( AF_GlyphHints hints, - AF_Dimension dim ) - { - AF_Point points = hints->points; - AF_Point point_limit = points + hints->num_points; - AF_Point* contour = hints->contours; - AF_Point* contour_limit = contour + hints->num_contours; - AF_Flags touch_flag; - AF_Point point; - AF_Point end_point; - AF_Point first_point; - - - /* PASS 1: Move segment points to edge positions */ - - if ( dim == AF_DIMENSION_HORZ ) - { - touch_flag = AF_FLAG_TOUCH_X; - - for ( point = points; point < point_limit; point++ ) - { - point->u = point->x; - point->v = point->ox; - } - } - else - { - touch_flag = AF_FLAG_TOUCH_Y; - - for ( point = points; point < point_limit; point++ ) - { - point->u = point->y; - point->v = point->oy; - } - } - - point = points; - - for ( ; contour < contour_limit; contour++ ) - { - point = *contour; - end_point = point->prev; - first_point = point; - - while ( point <= end_point && !( point->flags & touch_flag ) ) - point++; - - if ( point <= end_point ) - { - AF_Point first_touched = point; - AF_Point cur_touched = point; - - - point++; - while ( point <= end_point ) - { - if ( point->flags & touch_flag ) - { - /* we found two successive touched points; we interpolate */ - /* all contour points between them */ - af_iup_interp( cur_touched + 1, point - 1, - cur_touched, point ); - cur_touched = point; - } - point++; - } - - if ( cur_touched == first_touched ) - { - /* this is a special case: only one point was touched in the */ - /* contour; we thus simply shift the whole contour */ - af_iup_shift( first_point, end_point, cur_touched ); - } - else - { - /* now interpolate after the last touched point to the end */ - /* of the contour */ - af_iup_interp( cur_touched + 1, end_point, - cur_touched, first_touched ); - - /* if the first contour point isn't touched, interpolate */ - /* from the contour start to the first touched point */ - if ( first_touched > points ) - af_iup_interp( first_point, first_touched - 1, - cur_touched, first_touched ); - } - } - } - - /* now save the interpolated values back to x/y */ - if ( dim == AF_DIMENSION_HORZ ) - { - for ( point = points; point < point_limit; point++ ) - point->x = point->u; - } - else - { - for ( point = points; point < point_limit; point++ ) - point->y = point->u; - } - } - - - - +#include "afhints.h" + +#ifdef AF_DEBUG + +#include + + void + af_glyph_hints_dump_edges( AF_GlyphHints hints ) + { + AF_Edge edges; + AF_Edge edge_limit; + AF_Segment segments; + FT_Int dimension; + + + edges = hints->horz_edges; + edge_limit = edges + hints->num_hedges; + segments = hints->horz_segments; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_Edge edge; + + + printf ( "Table of %s edges:\n", + !dimension ? "vertical" : "horizontal" ); + printf ( " [ index | pos | dir | link |" + " serif | blue | opos | pos ]\n" ); + + for ( edge = edges; edge < edge_limit; edge++ ) + { + printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", + edge - edges, + (int)edge->fpos, + edge->dir == AF_DIR_UP + ? "up" + : ( edge->dir == AF_DIR_DOWN + ? "down" + : ( edge->dir == AF_DIR_LEFT + ? "left" + : ( edge->dir == AF_DIR_RIGHT + ? "right" + : "none" ) ) ), + edge->link ? ( edge->link - edges ) : -1, + edge->serif ? ( edge->serif - edges ) : -1, + edge->blue_edge ? 'y' : 'n', + edge->opos / 64.0, + edge->pos / 64.0 ); + } + + edges = hints->vert_edges; + edge_limit = edges + hints->num_vedges; + segments = hints->vert_segments; + } + } + + + /* A function used to dump the array of linked segments */ + void + af_glyph_hints_dump_segments( AF_GlyphHints hints ) + { + AF_Segment segments; + AF_Segment segment_limit; + AF_Point points; + FT_Int dimension; + + + points = hints->points; + segments = hints->horz_segments; + segment_limit = segments + hints->num_hsegments; + + for ( dimension = 1; dimension >= 0; dimension-- ) + { + AF_Segment seg; + + + printf ( "Table of %s segments:\n", + !dimension ? "vertical" : "horizontal" ); + printf ( " [ index | pos | dir | link | serif |" + " numl | first | start ]\n" ); + + for ( seg = segments; seg < segment_limit; seg++ ) + { + printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n", + seg - segments, + (int)seg->pos, + seg->dir == AF_DIR_UP + ? "up" + : ( seg->dir == AF_DIR_DOWN + ? "down" + : ( seg->dir == AF_DIR_LEFT + ? "left" + : ( seg->dir == AF_DIR_RIGHT + ? "right" + : "none" ) ) ), + seg->link ? ( seg->link - segments ) : -1, + seg->serif ? ( seg->serif - segments ) : -1, + (int)seg->num_linked, + seg->first - points, + seg->last - points ); + } + + segments = hints->vert_segments; + segment_limit = segments + hints->num_vsegments; + } + } + +#endif /* AF_DEBUG */ + + + /* compute the direction value of a given vector */ + FT_LOCAL_DEF( AF_Direction ) + af_direction_compute( FT_Pos dx, + FT_Pos dy ) + { + AF_Direction dir; + FT_Pos ax = ABS( dx ); + FT_Pos ay = ABS( dy ); + + + dir = AF_DIR_NONE; + + /* atan(1/12) == 4.7 degrees */ + + /* test for vertical direction */ + if ( ax * 12 < ay ) + { + dir = dy > 0 ? AF_DIR_UP : AF_DIR_DOWN; + } + /* test for horizontal direction */ + else if ( ay * 12 < ax ) + { + dir = dx > 0 ? AF_DIR_RIGHT : AF_DIR_LEFT; + } + + return dir; + } + + + /* compute all inflex points in a given glyph */ + static void + af_glyph_hints_compute_inflections( AF_GlyphHints hints ) + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + + + /* do each contour separately */ + for ( ; contour < contour_limit; contour++ ) + { + AF_Point point = contour[0]; + AF_Point first = point; + AF_Point start = point; + AF_Point end = point; + AF_Point before; + AF_Point after; + AF_Angle angle_in, angle_seg, angle_out; + AF_Angle diff_in, diff_out; + FT_Int finished = 0; + + + /* compute first segment in contour */ + first = point; + + start = end = first; + do + { + end = end->next; + if ( end == first ) + goto Skip; + + } while ( end->fx == first->fx && end->fy == first->fy ); + + angle_seg = af_angle_atan( end->fx - start->fx, + end->fy - start->fy ); + + /* extend the segment start whenever possible */ + before = start; + do + { + do + { + start = before; + before = before->prev; + if ( before == first ) + goto Skip; + + } while ( before->fx == start->fx && before->fy == start->fy ); + + angle_in = af_angle_atan( start->fx - before->fx, + start->fy - before->fy ); + + } while ( angle_in == angle_seg ); + + first = start; + diff_in = af_angle_diff( angle_in, angle_seg ); + + /* now, process all segments in the contour */ + do + { + /* first, extend current segment's end whenever possible */ + after = end; + do + { + do + { + end = after; + after = after->next; + if ( after == first ) + finished = 1; + + } while ( end->fx == after->fx && end->fy == after->fy ); + + angle_out = af_angle_atan( after->fx - end->fx, + after->fy - end->fy ); + + } while ( angle_out == angle_seg ); + + diff_out = af_angle_diff( angle_seg, angle_out ); + + if ( ( diff_in ^ diff_out ) < 0 ) + { + /* diff_in and diff_out have different signs, we have */ + /* inflection points here... */ + do + { + start->flags |= AF_FLAG_INFLECTION; + start = start->next; + + } while ( start != end ); + + start->flags |= AF_FLAG_INFLECTION; + } + + start = end; + end = after; + angle_seg = angle_out; + diff_in = diff_out; + + } while ( !finished ); + + Skip: + ; + } + } + + + + FT_LOCAL_DEF( void ) + af_glyph_hints_init( AF_GlyphHints hints, + FT_Memory memory ) + { + FT_ZERO( hints ); + hints->memory = memory; + } + + + + FT_LOCAL_DEF( void ) + af_glyph_hints_done( AF_GlyphHints hints ) + { + if ( hints && hints->memory ) + { + FT_Memory memory = hints->memory; + AF_Dimension dim; + + /* note that we don't need to free the segment and edge + * buffers, since they're really within the hints->points array + */ + for ( dim = 0; dim < 2; dim++ ) + { + AF_AxisHints axis = &hints->axis[ dim ]; + + axis->num_segments = 0; + axis->num_edges = 0; + axis->segments = NULL; + axis->edges = NULL; + } + + FT_FREE( hints->contours ); + hints->max_contours = 0; + hints->num_contours = 0; + + FT_FREE( hints->points ); + hints->num_points = 0; + hints->max_points = 0; + + hints->memory = NULL; + } + } + + + + FT_LOCAL_DEF( FT_Error ) + af_glyph_hints_reset( AF_GlyphHints hints, + AF_Scaler scaler, + FT_Outline* outline ) + { + FT_Error error = FT_Err_Ok; + AF_Point points; + FT_UInt old_max, new_max; + FT_Fixed x_scale = scaler->x_scale; + FT_Fixed y_scale = scaler->y_scale; + FT_Pos x_delta = scaler->x_delta; + FT_Pos y_delta = scaler->y_delta; + FT_Memory memory = hints->memory; + + hints->scaler_flags = scaler->flags; + hints->other_flags = 0; + + hints->num_points = 0; + hints->num_contours = 0; + + hints->axis[0].num_segments = 0; + hints->axis[0].num_edges = 0; + hints->axis[1].num_segments = 0; + hints->axis[1].num_edges = 0; + + /* first of all, reallocate the contours array when necessary + */ + new_max = (FT_UInt) outline->n_contours; + old_max = hints->max_contours; + if ( new_max > old_max ) + { + new_max = (new_max + 3) & ~3; + + if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) + goto Exit; + + hints->max_contours = new_max; + } + + /* then, reallocate the points, segments & edges arrays if needed -- + * note that we reserved two additional point positions, used to + * hint metrics appropriately + */ + new_max = (FT_UInt)( outline->n_points + 2 ); + old_max = hints->max_points; + if ( new_max > old_max ) + { + FT_Byte* items; + FT_ULong off1, off2, off3; + + /* we store in a single buffer the following arrays: + * + * - an array of N AF_PointRec items + * - an array of 2*N AF_SegmentRec items + * - an array of 2*N AF_EdgeRec items + * + */ + + new_max = ( new_max + 2 + 7 ) & ~7; + +#undef OFF_INCREMENT +#define OFF_INCREMENT( _off, _type, _count ) \ + ( FT_PAD_CEIL( _off, sizeof(_type) ) + (_count)*sizeof(_type)) + + off1 = OFF_INCREMENT( 0, AF_PointRec, new_max ); + off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max ); + off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 ); + + FT_FREE( hints->points ); + + if ( FT_ALLOC( items, off3 ) ) + { + hints->max_points = 0; + hints->axis[0].segments = NULL; + hints->axis[0].edges = NULL; + hints->axis[1].segments = NULL; + hints->axis[1].edges = NULL; + goto Exit; + } + + /* readjust some pointers + */ + hints->max_points = new_max; + hints->points = (AF_Point) items; + + hints->axis[0].segments = (AF_Segment)( items + off1 ); + hints->axis[1].segments = hints->axis[0].segments + new_max; + + hints->axis[0].edges = (AF_Edge) ( items + off2 ); + hints->axis[1].edges = hints->axis[0].edges + new_max; + } + + hints->num_points = outline->n_points; + hints->num_contours = outline->n_contours; + + + /* We can't rely on the value of `FT_Outline.flags' to know the fill */ + /* direction used for a glyph, given that some fonts are broken (e.g. */ + /* the Arphic ones). We thus recompute it each time we need to. */ + /* */ + hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_UP; + hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_LEFT; + + if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT ) + { + hints->axis[ AF_DIMENSION_HORZ ].major_dir = AF_DIR_DOWN; + hints->axis[ AF_DIMENSION_VERT ].major_dir = AF_DIR_RIGHT; + } + + 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; + + { + AF_Point point; + AF_Point point_limit = points + hints->num_points; + + + /* compute coordinates & bezier flags */ + { + FT_Vector* vec = outline->points; + char* tag = outline->tags; + + + for ( point = points; point < point_limit; point++, vec++, tag++ ) + { + point->fx = vec->x; + point->fy = vec->y; + point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta; + point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta; + + switch ( FT_CURVE_TAG( *tag ) ) + { + case FT_CURVE_TAG_CONIC: + point->flags = AF_FLAG_CONIC; + break; + case FT_CURVE_TAG_CUBIC: + point->flags = AF_FLAG_CUBIC; + break; + default: + point->flags = 0; + ; + } + } + } + + /* compute `next' and `prev' */ + { + FT_Int contour_index; + AF_Point prev; + AF_Point first; + AF_Point end; + + + contour_index = 0; + + first = points; + end = points + outline->contours[0]; + prev = end; + + for ( point = points; point < point_limit; point++ ) + { + point->prev = prev; + if ( point < end ) + { + point->next = point + 1; + prev = point; + } + else + { + point->next = first; + contour_index++; + if ( point + 1 < point_limit ) + { + end = points + outline->contours[contour_index]; + first = point + 1; + prev = end; + } + } + } + } + + /* set-up the contours array */ + { + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + short* end = outline->contours; + short idx = 0; + + + for ( ; contour < contour_limit; contour++, end++ ) + { + contour[0] = points + idx; + idx = (short)( end[0] + 1 ); + } + } + + /* compute directions of in & out vectors */ + { + for ( point = points; point < point_limit; point++ ) + { + AF_Point prev; + AF_Point next; + FT_Pos in_x, in_y, out_x, out_y; + + + prev = point->prev; + in_x = point->fx - prev->fx; + in_y = point->fy - prev->fy; + + point->in_dir = af_direction_compute( in_x, in_y ); + + next = point->next; + out_x = next->fx - point->fx; + out_y = next->fy - point->fy; + + point->out_dir = af_direction_compute( out_x, out_y ); + + if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) ) + { + Is_Weak_Point: + point->flags |= AF_FLAG_WEAK_INTERPOLATION; + } + else if ( point->out_dir == point->in_dir ) + { + AF_Angle angle_in, angle_out, delta; + + + if ( point->out_dir != AF_DIR_NONE ) + goto Is_Weak_Point; + + angle_in = af_angle_atan( in_x, in_y ); + angle_out = af_angle_atan( out_x, out_y ); + delta = af_angle_diff( angle_in, angle_out ); + + if ( delta < 2 && delta > -2 ) + goto Is_Weak_Point; + } + else if ( point->in_dir == -point->out_dir ) + goto Is_Weak_Point; + } + } + } + + /* compute inflection points + */ + af_glyph_hints_compute_inflections( hints ); + + Exit: + return error; + } + + + + + /* + * + * E D G E P O I N T G R I D - F I T T I N G + * + */ + + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_edge_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[ dim ]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge; + + for ( edge = edges; edge < edge_limit; edge++ ) + { + /* move the points of each segment */ + /* in each edge to the edge's position */ + AF_Segment seg = edge->first; + + + do + { + AF_Point point = seg->first; + + + for (;;) + { + if ( dim == AF_DIMENSION_HORZ ) + { + point->x = edge->pos; + point->flags |= AF_FLAG_TOUCH_X; + } + else + { + point->y = edge->pos; + point->flags |= AF_FLAG_TOUCH_Y; + } + + if ( point == seg->last ) + break; + + point = point->next; + } + + seg = seg->edge_next; + + } while ( seg != edge->first ); + } + } + + + /* + * + * S T R O N G P O I N T I N T E R P O L A T I O N + * + */ + + + /* hint the strong points -- this is equivalent to the TrueType `IP' */ + /* hinting instruction */ + FT_LOCAL_DEF( void ) + af_glyph_hints_align_strong_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_AxisHints axis = &hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + AF_Flags touch_flag; + + + if ( dim == AF_DIMENSION_HORZ ) + touch_flag = AF_FLAG_TOUCH_X; + else + touch_flag = AF_FLAG_TOUCH_Y; + + if ( edges < edge_limit ) + { + AF_Point point; + AF_Edge edge; + + for ( point = points; point < point_limit; point++ ) + { + FT_Pos u, ou, fu; /* point position */ + FT_Pos delta; + + + if ( point->flags & touch_flag ) + continue; + + /* if this point is candidate to weak interpolation, we will */ + /* interpolate it after all strong points have been processed */ + if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) && + !( point->flags & AF_FLAG_INFLECTION ) ) + continue; + + if ( dim == AF_DIMENSION_VERT ) + { + u = point->fy; + ou = point->oy; + } + else + { + u = point->fx; + ou = point->ox; + } + + fu = u; + + /* is the point before the first edge? */ + edge = edges; + delta = edge->fpos - u; + if ( delta >= 0 ) + { + u = edge->pos - ( edge->opos - ou ); + goto Store_Point; + } + + /* is the point after the last edge? */ + edge = edge_limit - 1; + delta = u - edge->fpos; + if ( delta >= 0 ) + { + u = edge->pos + ( ou - edge->opos ); + goto Store_Point; + } + + { + FT_UInt min, max, mid; + FT_Pos fpos; + + + /* find enclosing edges */ + min = 0; + max = edge_limit - edges; + + while ( min < max ) + { + mid = ( max + min ) >> 1; + edge = edges + mid; + fpos = edge->fpos; + + if ( u < fpos ) + max = mid; + else if ( u > fpos ) + min = mid + 1; + else + { + /* we are on the edge */ + u = edge->pos; + goto Store_Point; + } + } + + { + AF_Edge before = edges + min - 1; + AF_Edge after = edges + min + 0; + + + /* assert( before && after && before != after ) */ + if ( before->scale == 0 ) + before->scale = FT_DivFix( after->pos - before->pos, + after->fpos - before->fpos ); + + u = before->pos + FT_MulFix( fu - before->fpos, + before->scale ); + } + } + + + Store_Point: + + /* save the point position */ + if ( dim == AF_DIMENSION_HORZ ) + point->x = u; + else + point->y = u; + + point->flags |= touch_flag; + } + } + } + + + /* + * + * W E A K P O I N T I N T E R P O L A T I O N + * + */ + + static void + af_iup_shift( AF_Point p1, + AF_Point p2, + AF_Point ref ) + { + AF_Point p; + FT_Pos delta = ref->u - ref->v; + + + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } + + + static void + af_iup_interp( AF_Point p1, + AF_Point p2, + AF_Point ref1, + AF_Point ref2 ) + { + AF_Point p; + FT_Pos u; + FT_Pos v1 = ref1->v; + FT_Pos v2 = ref2->v; + FT_Pos d1 = ref1->u - v1; + FT_Pos d2 = ref2->u - v2; + + + if ( p1 > p2 ) + return; + + if ( v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else + u += d2; + + p->u = u; + } + return; + } + + if ( v1 < v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + else + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v2 ) + u += d2; + else if ( u >= v1 ) + u += d1; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Flags touch_flag; + AF_Point point; + AF_Point end_point; + AF_Point first_point; + + + /* PASS 1: Move segment points to edge positions */ + + if ( dim == AF_DIMENSION_HORZ ) + { + touch_flag = AF_FLAG_TOUCH_X; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->x; + point->v = point->ox; + } + } + else + { + touch_flag = AF_FLAG_TOUCH_Y; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->y; + point->v = point->oy; + } + } + + point = points; + + for ( ; contour < contour_limit; contour++ ) + { + point = *contour; + end_point = point->prev; + first_point = point; + + while ( point <= end_point && !( point->flags & touch_flag ) ) + point++; + + if ( point <= end_point ) + { + AF_Point first_touched = point; + AF_Point cur_touched = point; + + + point++; + while ( point <= end_point ) + { + if ( point->flags & touch_flag ) + { + /* we found two successive touched points; we interpolate */ + /* all contour points between them */ + af_iup_interp( cur_touched + 1, point - 1, + cur_touched, point ); + cur_touched = point; + } + point++; + } + + if ( cur_touched == first_touched ) + { + /* this is a special case: only one point was touched in the */ + /* contour; we thus simply shift the whole contour */ + af_iup_shift( first_point, end_point, cur_touched ); + } + else + { + /* now interpolate after the last touched point to the end */ + /* of the contour */ + af_iup_interp( cur_touched + 1, end_point, + cur_touched, first_touched ); + + /* if the first contour point isn't touched, interpolate */ + /* from the contour start to the first touched point */ + if ( first_touched > points ) + af_iup_interp( first_point, first_touched - 1, + cur_touched, first_touched ); + } + } + } + + /* now save the interpolated values back to x/y */ + if ( dim == AF_DIMENSION_HORZ ) + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + } + else + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + } + } diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c index 69738dd88..f51a6cf2b 100644 --- a/src/autofit/afloader.c +++ b/src/autofit/afloader.c @@ -1,431 +1,431 @@ -#include "afloader.h" -#include "afhints.h" -#include "afglobal.h" -#include "aflatin.h" - - FT_LOCAL_DEF( FT_Error ) - af_loader_init( AF_Loader loader, - FT_Memory memory ) - { - FT_Error error; - - FT_ZERO( loader ); - - af_glyph_hints_init( &loader->hints, memory ); - - error = FT_GlyphLoader_New( memory, &loader->gloader ); - if ( !error ) - { - error = FT_GlyphLoader_CreateExtra( loader->gloader ); - if ( error ) - { - FT_GlyphLoader_Done( loader->gloader ); - loader->gloader = NULL; - } - } - return error; - } - - - FT_LOCAL_DEF( FT_Error ) - af_loader_reset( AF_Loader loader, - FT_Face face ) - { - FT_Error error = 0; - - loader->face = face; - loader->gloader = face->glyph->internal->loader; - loader->globals = (AF_FaceGlobals) face->autohint.data; - - if ( loader->globals == NULL ) - { - error = af_face_globals_new( face, &loader->globals ); - if ( !error ) - { - face->autohint.data = (FT_Pointer) loader->globals; - face->autohint.finalizer = (FT_Generic_Finalizer) af_face_globals_free; - } - } - return error; - } - - - FT_LOCAL_DEF( void ) - af_loader_done( AF_Loader loader ) - { - loader->face = NULL; - loader->globals = NULL; - - FT_GlyphLoader_Done( loader->gloader ); - loader->gloader = NULL; - } - - - static FT_Error - af_loader_load_g( AF_Loader loader, - AF_Scaler scaler, - FT_UInt glyph_index, - FT_Int32 load_flags, - FT_UInt depth ) - { - FT_Error error = 0; - FT_Face face = loader->face; - AF_FaceGlobals globals = loader->globals; - FT_GlyphLoader gloader = loader->gloader; - AF_ScriptMetrics metrics = loader->metrics; - AF_GlyphHints hints = &loader->hints; - FT_GlyphSlot slot = face->glyph; - FT_Slot_Internal internal = slot->internal; - - error = FT_Load_Glyph( face, glyph_index, load_flags ); - if ( error ) - goto Exit; - - loader->transformed = internal->glyph_transformed; - if ( loader->transformed ) - { - FT_Matrix inverse; - - loader->trans_matrix = internal->glyph_matrix; - loader->trans_delta = internal->glyph_delta; - - inverse = loader->trans_matrix; - FT_Matrix_Invert( &inverse ); - FT_Vector_Transform( &loader->trans_delta, &inverse ); - } - - /* set linear metrics */ - slot->linearHoriAdvance = slot->metrics.horiAdvance; - slot->linearVertAdvance = slot->metrics.vertAdvance; - - switch ( slot->format ) - { - case FT_GLYPH_FORMAT_OUTLINE: - /* translate the loaded glyph when an internal transform - * is needed - */ - if ( loader->transformed ) - { - FT_Vector* point = slot->outline.points; - FT_Vector* limit = point + slot->outline.n_points; - - for ( ; point < limit; point++ ) - { - point->x += loader->trans_delta.x; - point->y += loader->trans_delta.y; - } - } - - /* copy the outline points in the loader's current */ - /* extra points which is used to keep original glyph coordinates */ - error = FT_GlyphLoader_CheckPoints( gloader, - slot->outline.n_points + 2, - slot->outline.n_contours ); - if ( error ) - goto Exit; - - FT_ARRAY_COPY( gloader->current.extra_points, - slot->outline.points, - slot->outline.n_points ); - - FT_ARRAY_COPY( gloader->current.outline.contours, - slot->outline.contours, - slot->outline.n_contours ); - - FT_ARRAY_COPY( gloader->current.outline.tags, - slot->outline.tags, - slot->outline.n_points ); - - gloader->current.outline.n_points = slot->outline.n_points; - gloader->current.outline.n_contours = slot->outline.n_contours; - - /* compute original phantom points */ - loader->pp1.x = hints->x_delta; - loader->pp1.y = hints->y_delta; - loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, - hints->x_scale ) + hints->x_delta; - loader->pp2.y = hints->y_delta; - - /* be sure to check for spacing glyphs */ - if ( slot->outline.n_points == 0 ) - goto Hint_Metrics; - - /* now load the slot image into the auto-outline and run the */ - /* automatic hinting process */ - error = metrics->clazz->script_hints_init( hints, - &gloader->current.outline, - metrics ); - if ( error ) - goto Exit; - - /* apply the hints */ - metrics->clazz->script_hints_apply( hints, - &gloader->current.outline, - metrics ); - /* we now need to hint the metrics according to the change in */ - /* width/positioning that occured during the hinting process */ - { - FT_Pos old_advance, old_rsb, old_lsb, new_lsb; - AF_AxisHints axis = &hints->axis[ AF_DIMENSION_HORZ ]; - AF_Edge edge1 = axis->edges; /* leftmost edge */ - AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ - - - old_advance = loader->pp2.x; - old_rsb = old_advance - edge2->opos; - old_lsb = edge1->opos; - new_lsb = edge1->pos; - - loader->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb ); - loader->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb ); - -#if 0 - /* try to fix certain bad advance computations */ - if ( loader->pp2.x + loader->pp1.x == edge2->pos && old_rsb > 4 ) - loader->pp2.x += 64; -#endif - } - - /* good, we simply add the glyph to our loader's base */ - FT_GlyphLoader_Add( gloader ); - break; - - case FT_GLYPH_FORMAT_COMPOSITE: - { - FT_UInt nn, num_subglyphs = slot->num_subglyphs; - FT_UInt num_base_subgs, start_point; - FT_SubGlyph subglyph; - - - start_point = gloader->base.outline.n_points; - - /* first of all, copy the subglyph descriptors in the glyph loader */ - error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); - if ( error ) - goto Exit; - - FT_ARRAY_COPY( gloader->current.subglyphs, - slot->subglyphs, - num_subglyphs ); - - gloader->current.num_subglyphs = num_subglyphs; - num_base_subgs = gloader->base.num_subglyphs; - - /* now, read each subglyph independently */ - for ( nn = 0; nn < num_subglyphs; nn++ ) - { - FT_Vector pp1, pp2; - FT_Pos x, y; - FT_UInt num_points, num_new_points, num_base_points; - - - /* gloader.current.subglyphs can change during glyph loading due */ - /* to re-allocation -- we must recompute the current subglyph on */ - /* each iteration */ - subglyph = gloader->base.subglyphs + num_base_subgs + nn; - - pp1 = loader->pp1; - pp2 = loader->pp2; - - num_base_points = gloader->base.outline.n_points; - - error = af_loader_load_g( loader, scaler, subglyph->index, - load_flags, depth + 1 ); - if ( error ) - goto Exit; - - /* recompute subglyph pointer */ - subglyph = gloader->base.subglyphs + num_base_subgs + nn; - - if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) - { - pp1 = loader->pp1; - pp2 = loader->pp2; - } - else - { - loader->pp1 = pp1; - loader->pp2 = pp2; - } - - num_points = gloader->base.outline.n_points; - num_new_points = num_points - num_base_points; - - /* now perform the transform required for this subglyph */ - - if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | - FT_SUBGLYPH_FLAG_XY_SCALE | - FT_SUBGLYPH_FLAG_2X2 ) ) - { - FT_Vector* cur = gloader->base.outline.points + - num_base_points; - FT_Vector* org = gloader->base.extra_points + - num_base_points; - FT_Vector* limit = cur + num_new_points; - - - for ( ; cur < limit; cur++, org++ ) - { - FT_Vector_Transform( cur, &subglyph->transform ); - FT_Vector_Transform( org, &subglyph->transform ); - } - } - - /* apply offset */ - - if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) - { - FT_Int k = subglyph->arg1; - FT_UInt l = subglyph->arg2; - FT_Vector* p1; - FT_Vector* p2; - - - if ( start_point + k >= num_base_points || - l >= (FT_UInt)num_new_points ) - { - error = FT_Err_Invalid_Composite; - goto Exit; - } - - l += num_base_points; - - /* for now, only use the current point coordinates; */ - /* we may consider another approach in the near future */ - p1 = gloader->base.outline.points + start_point + k; - p2 = gloader->base.outline.points + start_point + l; - - x = p1->x - p2->x; - y = p1->y - p2->y; - } - else - { - x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; - y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; - - x = FT_PIX_ROUND(x); - y = FT_PIX_ROUND(y); - } - - { - FT_Outline dummy = gloader->base.outline; - - - dummy.points += num_base_points; - dummy.n_points = (short)num_new_points; - - FT_Outline_Translate( &dummy, x, y ); - } - } - } - break; - - default: - /* we don't support other formats (yet?) */ - error = FT_Err_Unimplemented_Feature; - } - - Hint_Metrics: - if ( depth == 0 ) - { - FT_BBox bbox; - - - /* transform the hinted outline if needed */ - if ( loader->transformed ) - FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); - - /* we must translate our final outline by -pp1.x and compute */ - /* the new metrics */ - if ( loader->pp1.x ) - FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); - - FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); - - bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); - bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); - bbox.xMax = FT_PIX_CEIL( bbox.xMax ); - bbox.yMax = FT_PIX_CEIL( bbox.yMax ); - - slot->metrics.width = bbox.xMax - bbox.xMin; - slot->metrics.height = bbox.yMax - bbox.yMin; - slot->metrics.horiBearingX = bbox.xMin; - slot->metrics.horiBearingY = bbox.yMax; - - /* for mono-width fonts (like Andale, Courier, etc.) we need */ - /* to keep the original rounded advance width */ -#if 0 - if ( !FT_IS_FIXED_WIDTH( slot->face ) ) - slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; - else - slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, - x_scale ); -#else - slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; -#endif - - slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); - - /* now copy outline into glyph slot */ - FT_GlyphLoader_Rewind( loader->gloader ); - error = FT_GlyphLoader_CopyPoints( loader->gloader, gloader ); - if ( error ) - goto Exit; - - slot->outline = slot->internal->loader->base.outline; - slot->format = FT_GLYPH_FORMAT_OUTLINE; - } - -#ifdef DEBUG_HINTER - af_debug_hinter = hinter; -#endif - - Exit: - return error; - } - - - - - FT_LOCAL_DEF( FT_Error ) - af_loader_load_glyph( AF_Loader loader, - FT_Face face, - FT_UInt gindex, - FT_UInt32 load_flags ) - { - FT_Error error; - FT_Size size = face->size; - AF_ScalerRec scaler; - - if ( !size ) - return FT_Err_Invalid_Argument; - - FT_ZERO( &scaler ); - - scaler.face = face; - scaler.x_scale = size->metrics.x_scale; - scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ - scaler.y_scale = size->metrics.y_scale; - scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ - - scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); - scaler.flags = 0; /* XXX: fix this */ - - error = af_loader_reset( loader, face ); - if ( !error ) - { - AF_ScriptMetrics metrics; - - error = af_face_globals_get_metrics( loader->globals, gindex, &metrics ); - if ( !error ) - { - metrics->clazz->script_metrics_scale( metrics, &scaler ); - - load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; - load_flags &= ~FT_LOAD_RENDER; - - error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); - } - } - return error; - } +#include "afloader.h" +#include "afhints.h" +#include "afglobal.h" +#include "aflatin.h" + + FT_LOCAL_DEF( FT_Error ) + af_loader_init( AF_Loader loader, + FT_Memory memory ) + { + FT_Error error; + + FT_ZERO( loader ); + + af_glyph_hints_init( &loader->hints, memory ); + + error = FT_GlyphLoader_New( memory, &loader->gloader ); + if ( !error ) + { + error = FT_GlyphLoader_CreateExtra( loader->gloader ); + if ( error ) + { + FT_GlyphLoader_Done( loader->gloader ); + loader->gloader = NULL; + } + } + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + af_loader_reset( AF_Loader loader, + FT_Face face ) + { + FT_Error error = 0; + + loader->face = face; + loader->gloader = face->glyph->internal->loader; + loader->globals = (AF_FaceGlobals) face->autohint.data; + + if ( loader->globals == NULL ) + { + error = af_face_globals_new( face, &loader->globals ); + if ( !error ) + { + face->autohint.data = (FT_Pointer) loader->globals; + face->autohint.finalizer = (FT_Generic_Finalizer) af_face_globals_free; + } + } + return error; + } + + + FT_LOCAL_DEF( void ) + af_loader_done( AF_Loader loader ) + { + loader->face = NULL; + loader->globals = NULL; + + FT_GlyphLoader_Done( loader->gloader ); + loader->gloader = NULL; + } + + + static FT_Error + af_loader_load_g( AF_Loader loader, + AF_Scaler scaler, + FT_UInt glyph_index, + FT_Int32 load_flags, + FT_UInt depth ) + { + FT_Error error = 0; + FT_Face face = loader->face; + AF_FaceGlobals globals = loader->globals; + FT_GlyphLoader gloader = loader->gloader; + AF_ScriptMetrics metrics = loader->metrics; + AF_GlyphHints hints = &loader->hints; + FT_GlyphSlot slot = face->glyph; + FT_Slot_Internal internal = slot->internal; + + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + goto Exit; + + loader->transformed = internal->glyph_transformed; + if ( loader->transformed ) + { + FT_Matrix inverse; + + loader->trans_matrix = internal->glyph_matrix; + loader->trans_delta = internal->glyph_delta; + + inverse = loader->trans_matrix; + FT_Matrix_Invert( &inverse ); + FT_Vector_Transform( &loader->trans_delta, &inverse ); + } + + /* set linear metrics */ + slot->linearHoriAdvance = slot->metrics.horiAdvance; + slot->linearVertAdvance = slot->metrics.vertAdvance; + + switch ( slot->format ) + { + case FT_GLYPH_FORMAT_OUTLINE: + /* translate the loaded glyph when an internal transform + * is needed + */ + if ( loader->transformed ) + { + FT_Vector* point = slot->outline.points; + FT_Vector* limit = point + slot->outline.n_points; + + for ( ; point < limit; point++ ) + { + point->x += loader->trans_delta.x; + point->y += loader->trans_delta.y; + } + } + + /* copy the outline points in the loader's current */ + /* extra points which is used to keep original glyph coordinates */ + error = FT_GlyphLoader_CheckPoints( gloader, + slot->outline.n_points + 2, + slot->outline.n_contours ); + if ( error ) + goto Exit; + + FT_ARRAY_COPY( gloader->current.extra_points, + slot->outline.points, + slot->outline.n_points ); + + FT_ARRAY_COPY( gloader->current.outline.contours, + slot->outline.contours, + slot->outline.n_contours ); + + FT_ARRAY_COPY( gloader->current.outline.tags, + slot->outline.tags, + slot->outline.n_points ); + + gloader->current.outline.n_points = slot->outline.n_points; + gloader->current.outline.n_contours = slot->outline.n_contours; + + /* compute original phantom points */ + loader->pp1.x = hints->x_delta; + loader->pp1.y = hints->y_delta; + loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, + hints->x_scale ) + hints->x_delta; + loader->pp2.y = hints->y_delta; + + /* be sure to check for spacing glyphs */ + if ( slot->outline.n_points == 0 ) + goto Hint_Metrics; + + /* now load the slot image into the auto-outline and run the */ + /* automatic hinting process */ + error = metrics->clazz->script_hints_init( hints, + &gloader->current.outline, + metrics ); + if ( error ) + goto Exit; + + /* apply the hints */ + metrics->clazz->script_hints_apply( hints, + &gloader->current.outline, + metrics ); + /* we now need to hint the metrics according to the change in */ + /* width/positioning that occured during the hinting process */ + { + FT_Pos old_advance, old_rsb, old_lsb, new_lsb; + AF_AxisHints axis = &hints->axis[ AF_DIMENSION_HORZ ]; + AF_Edge edge1 = axis->edges; /* leftmost edge */ + AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ + + + old_advance = loader->pp2.x; + old_rsb = old_advance - edge2->opos; + old_lsb = edge1->opos; + new_lsb = edge1->pos; + + loader->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb ); + loader->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb ); + +#if 0 + /* try to fix certain bad advance computations */ + if ( loader->pp2.x + loader->pp1.x == edge2->pos && old_rsb > 4 ) + loader->pp2.x += 64; +#endif + } + + /* good, we simply add the glyph to our loader's base */ + FT_GlyphLoader_Add( gloader ); + break; + + case FT_GLYPH_FORMAT_COMPOSITE: + { + FT_UInt nn, num_subglyphs = slot->num_subglyphs; + FT_UInt num_base_subgs, start_point; + FT_SubGlyph subglyph; + + + start_point = gloader->base.outline.n_points; + + /* first of all, copy the subglyph descriptors in the glyph loader */ + error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs ); + if ( error ) + goto Exit; + + FT_ARRAY_COPY( gloader->current.subglyphs, + slot->subglyphs, + num_subglyphs ); + + gloader->current.num_subglyphs = num_subglyphs; + num_base_subgs = gloader->base.num_subglyphs; + + /* now, read each subglyph independently */ + for ( nn = 0; nn < num_subglyphs; nn++ ) + { + FT_Vector pp1, pp2; + FT_Pos x, y; + FT_UInt num_points, num_new_points, num_base_points; + + + /* gloader.current.subglyphs can change during glyph loading due */ + /* to re-allocation -- we must recompute the current subglyph on */ + /* each iteration */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + + pp1 = loader->pp1; + pp2 = loader->pp2; + + num_base_points = gloader->base.outline.n_points; + + error = af_loader_load_g( loader, scaler, subglyph->index, + load_flags, depth + 1 ); + if ( error ) + goto Exit; + + /* recompute subglyph pointer */ + subglyph = gloader->base.subglyphs + num_base_subgs + nn; + + if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) + { + pp1 = loader->pp1; + pp2 = loader->pp2; + } + else + { + loader->pp1 = pp1; + loader->pp2 = pp2; + } + + num_points = gloader->base.outline.n_points; + num_new_points = num_points - num_base_points; + + /* now perform the transform required for this subglyph */ + + if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | + FT_SUBGLYPH_FLAG_XY_SCALE | + FT_SUBGLYPH_FLAG_2X2 ) ) + { + FT_Vector* cur = gloader->base.outline.points + + num_base_points; + FT_Vector* org = gloader->base.extra_points + + num_base_points; + FT_Vector* limit = cur + num_new_points; + + + for ( ; cur < limit; cur++, org++ ) + { + FT_Vector_Transform( cur, &subglyph->transform ); + FT_Vector_Transform( org, &subglyph->transform ); + } + } + + /* apply offset */ + + if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) + { + FT_Int k = subglyph->arg1; + FT_UInt l = subglyph->arg2; + FT_Vector* p1; + FT_Vector* p2; + + + if ( start_point + k >= num_base_points || + l >= (FT_UInt)num_new_points ) + { + error = FT_Err_Invalid_Composite; + goto Exit; + } + + l += num_base_points; + + /* for now, only use the current point coordinates; */ + /* we may consider another approach in the near future */ + p1 = gloader->base.outline.points + start_point + k; + p2 = gloader->base.outline.points + start_point + l; + + x = p1->x - p2->x; + y = p1->y - p2->y; + } + else + { + x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta; + y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta; + + x = FT_PIX_ROUND(x); + y = FT_PIX_ROUND(y); + } + + { + FT_Outline dummy = gloader->base.outline; + + + dummy.points += num_base_points; + dummy.n_points = (short)num_new_points; + + FT_Outline_Translate( &dummy, x, y ); + } + } + } + break; + + default: + /* we don't support other formats (yet?) */ + error = FT_Err_Unimplemented_Feature; + } + + Hint_Metrics: + if ( depth == 0 ) + { + FT_BBox bbox; + + + /* transform the hinted outline if needed */ + if ( loader->transformed ) + FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); + + /* we must translate our final outline by -pp1.x and compute */ + /* the new metrics */ + if ( loader->pp1.x ) + FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); + + FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); + + bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); + bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); + bbox.xMax = FT_PIX_CEIL( bbox.xMax ); + bbox.yMax = FT_PIX_CEIL( bbox.yMax ); + + slot->metrics.width = bbox.xMax - bbox.xMin; + slot->metrics.height = bbox.yMax - bbox.yMin; + slot->metrics.horiBearingX = bbox.xMin; + slot->metrics.horiBearingY = bbox.yMax; + + /* for mono-width fonts (like Andale, Courier, etc.) we need */ + /* to keep the original rounded advance width */ +#if 0 + if ( !FT_IS_FIXED_WIDTH( slot->face ) ) + slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; + else + slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, + x_scale ); +#else + slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; +#endif + + slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); + + /* now copy outline into glyph slot */ + FT_GlyphLoader_Rewind( loader->gloader ); + error = FT_GlyphLoader_CopyPoints( loader->gloader, gloader ); + if ( error ) + goto Exit; + + slot->outline = slot->internal->loader->base.outline; + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + +#ifdef DEBUG_HINTER + af_debug_hinter = hinter; +#endif + + Exit: + return error; + } + + + + + FT_LOCAL_DEF( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + FT_Face face, + FT_UInt gindex, + FT_UInt32 load_flags ) + { + FT_Error error; + FT_Size size = face->size; + AF_ScalerRec scaler; + + if ( !size ) + return FT_Err_Invalid_Argument; + + FT_ZERO( &scaler ); + + scaler.face = face; + scaler.x_scale = size->metrics.x_scale; + scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ + scaler.y_scale = size->metrics.y_scale; + scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ + + scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); + scaler.flags = 0; /* XXX: fix this */ + + error = af_loader_reset( loader, face ); + if ( !error ) + { + AF_ScriptMetrics metrics; + + error = af_face_globals_get_metrics( loader->globals, gindex, &metrics ); + if ( !error ) + { + metrics->clazz->script_metrics_scale( metrics, &scaler ); + + load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; + load_flags &= ~FT_LOAD_RENDER; + + error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); + } + } + return error; + } diff --git a/src/autofit/afloader.h b/src/autofit/afloader.h index 7bff19239..b4a8417cd 100644 --- a/src/autofit/afloader.h +++ b/src/autofit/afloader.h @@ -1,50 +1,49 @@ -#ifndef __AF_LOADER_H__ -#define __AF_LOADER_H__ - -#include "afhints.h" -#include "afglobal.h" - -FT_BEGIN_HEADER - - typedef struct AF_LoaderRec_ - { - FT_Face face; /* current face */ - AF_FaceGlobals globals; /* current face globals */ - FT_GlyphLoader gloader; /* glyph loader */ - AF_GlyphHintsRec hints; - AF_ScriptMetrics metrics; - FT_Bool transformed; - FT_Matrix trans_matrix; - FT_Vector trans_delta; - FT_Vector pp1; - FT_Vector pp2; - - } AF_LoaderRec, *AF_Loader; - - - FT_LOCAL( FT_Error ) - af_loader_init( AF_Loader loader, - FT_Memory memory ); - - - FT_LOCAL( FT_Error ) - af_loader_reset( AF_Loader loader, - FT_Face face ); - - - FT_LOCAL( void ) - af_loader_done( AF_Loader loader ); - - - FT_LOCAL( FT_Error ) - af_loader_load_glyph( AF_Loader loader, - FT_Face face, - FT_UInt gindex, - FT_UInt32 load_flags ); - -/* */ - -FT_END_HEADER - -#endif /* __AF_LOADER_H__ */ - +#ifndef __AF_LOADER_H__ +#define __AF_LOADER_H__ + +#include "afhints.h" +#include "afglobal.h" + +FT_BEGIN_HEADER + + typedef struct AF_LoaderRec_ + { + FT_Face face; /* current face */ + AF_FaceGlobals globals; /* current face globals */ + FT_GlyphLoader gloader; /* glyph loader */ + AF_GlyphHintsRec hints; + AF_ScriptMetrics metrics; + FT_Bool transformed; + FT_Matrix trans_matrix; + FT_Vector trans_delta; + FT_Vector pp1; + FT_Vector pp2; + + } AF_LoaderRec, *AF_Loader; + + + FT_LOCAL( FT_Error ) + af_loader_init( AF_Loader loader, + FT_Memory memory ); + + + FT_LOCAL( FT_Error ) + af_loader_reset( AF_Loader loader, + FT_Face face ); + + + FT_LOCAL( void ) + af_loader_done( AF_Loader loader ); + + + FT_LOCAL( FT_Error ) + af_loader_load_glyph( AF_Loader loader, + FT_Face face, + FT_UInt gindex, + FT_UInt32 load_flags ); + +/* */ + +FT_END_HEADER + +#endif /* __AF_LOADER_H__ */ diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h index fec4f2075..b898cb375 100644 --- a/src/autofit/afmodule.h +++ b/src/autofit/afmodule.h @@ -1,17 +1,16 @@ -#ifndef __AFMODULE_H__ -#define __AFMODULE_H__ - -#include -#include FT_MODULE_H - - -FT_BEGIN_HEADER - - FT_CALLBACK_TABLE - const FT_Module_Class autofit_module_class; - - -FT_END_HEADER - -#endif /* __AFMODULE_H__ */ - +#ifndef __AFMODULE_H__ +#define __AFMODULE_H__ + +#include +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + FT_CALLBACK_TABLE + const FT_Module_Class autofit_module_class; + + +FT_END_HEADER + +#endif /* __AFMODULE_H__ */ diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index ad7084fdd..91e4db307 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -1,10 +1,8 @@ -#define FT_MAKE_OPTION_SINGLE_OBJECT -#include -#include "afangles.c" -#include "afglobal.c" -#include "afhints.c" -#include "aflatin.c" -#include "afloader.c" -#include "afmodule.c" - - +#define FT_MAKE_OPTION_SINGLE_OBJECT +#include +#include "afangles.c" +#include "afglobal.c" +#include "afhints.c" +#include "aflatin.c" +#include "afloader.c" +#include "afmodule.c" diff --git a/src/autohint/ahmodule.c b/src/autohint/ahmodule.c index 336fdcbeb..8fce31d61 100644 --- a/src/autohint/ahmodule.c +++ b/src/autohint/ahmodule.c @@ -117,7 +117,7 @@ FT_CALLBACK_TABLE_DEF - const FT_Module_Class autofit_module_class = + const FT_Module_Class autohint_module_class = { FT_MODULE_HINTER, sizeof ( FT_AutoHinterRec ), diff --git a/src/cache/Jamfile b/src/cache/Jamfile index 3b64863ec..b269c9557 100644 --- a/src/cache/Jamfile +++ b/src/cache/Jamfile @@ -1,4 +1,4 @@ -# FreeType 2 src/cache Jamfile (c) 2001, 2003 David Turner +# FreeType 2 src/cache Jamfile (c) 2001, 2003, 2004 David Turner # SubDir FT2_TOP $(FT2_SRC_DIR) cache ; diff --git a/src/cache/descrip.mms b/src/cache/descrip.mms index ee165798d..4d967dc18 100644 --- a/src/cache/descrip.mms +++ b/src/cache/descrip.mms @@ -3,7 +3,7 @@ # -# Copyright 2001, 2002, 2003 by +# Copyright 2001, 2002, 2003, 2004 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c index a989336e5..f7d7ab048 100644 --- a/src/cache/ftcbasic.c +++ b/src/cache/ftcbasic.c @@ -4,7 +4,7 @@ /* */ /* The FreeType basic cache interface (body). */ /* */ -/* Copyright 2003 by */ +/* Copyright 2003, 2004 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c index 4861b797a..63dea4924 100644 --- a/src/cache/ftccmap.c +++ b/src/cache/ftccmap.c @@ -4,7 +4,7 @@ /* */ /* FreeType CharMap cache (body) */ /* */ -/* Copyright 2000-2001, 2002, 2003 by */ +/* Copyright 2000-2001, 2002, 2003, 2004 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/src/cache/ftcmru.c b/src/cache/ftcmru.c index 18df02074..4b2a7fff5 100644 --- a/src/cache/ftcmru.c +++ b/src/cache/ftcmru.c @@ -4,7 +4,7 @@ /* */ /* FreeType MRU support (body). */ /* */ -/* Copyright 2003 by */ +/* Copyright 2003, 2004 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ diff --git a/src/sfnt/Jamfile b/src/sfnt/Jamfile index 9727c0640..257b3442c 100644 --- a/src/sfnt/Jamfile +++ b/src/sfnt/Jamfile @@ -1,4 +1,4 @@ -# FreeType 2 src/sfnt Jamfile (c) 2001, 2002 David Turner +# FreeType 2 src/sfnt Jamfile (c) 2001, 2002, 2004 David Turner # SubDir FT2_TOP $(FT2_SRC_DIR) sfnt ; diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 543bd1841..960171692 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -787,10 +787,11 @@ FT_Byte* limit = parser->root.limit; - /* the binary data has the following format */ - /* */ - /* `size' [white*] RD white ....... ND */ - /* */ + /* the binary data has one of the following formats */ + /* */ + /* `size' [white*] RD white ....... ND */ + /* `size' [white*] -| white ....... |- */ + /* */ T1_Skip_Spaces( parser ); @@ -1116,7 +1117,7 @@ /* (bound to `noaccess put') or by two separate tokens: */ /* `noaccess' & `put'. We position the parser right */ /* before the next `dup', if any. */ - T1_Skip_PS_Token( parser ); /* `NP' or `I' or `noaccess' */ + T1_Skip_PS_Token( parser ); /* `NP' or `|' or `noaccess' */ T1_Skip_Spaces ( parser ); if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 ) @@ -1487,7 +1488,8 @@ FT_Byte* keyword_flags ) { T1_Parser parser = &loader->parser; - FT_Byte* limit; + FT_Byte *limit, *start_binary; + FT_Bool have_integer; parser->root.cursor = base; @@ -1543,6 +1545,7 @@ cur2 = parser->root.cursor; } parser->root.cursor = cur2; + have_integer = 0; } /* look for `eexec' */ @@ -1555,6 +1558,43 @@ ft_strncmp( (char*)cur, "closefile", 9 ) == 0 ) break; + /* check whether we have an integer */ + else if ( ft_isdigit( *cur ) ) + { + start_binary = cur; + T1_Skip_PS_Token( parser ); + have_integer = 1; + } + + /* in valid Type 1 fonts we don't see `RD' or `-|' directly */ + /* since those tokens are handled by parse_subrs and */ + /* parse_charstrings */ + else if ( *cur == 'R' && cur + 6 < limit && *(cur + 1) == 'D' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } + + else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && + have_integer ) + { + FT_Long s; + FT_Byte* b; + + + parser->root.cursor = start_binary; + if ( !read_binary_data( parser, &s, &b ) ) + return T1_Err_Invalid_File_Format; + have_integer = 0; + } + /* look for immediates */ else if ( *cur == '/' && cur + 2 < limit ) { @@ -1582,10 +1622,7 @@ name = (FT_Byte*)keyword->ident; if ( !name ) - { - T1_Skip_PS_Token( parser ); break; - } if ( cur[0] == name[0] && len == ft_strlen( (const char *)name ) && @@ -1614,9 +1651,14 @@ keyword_flag++; } } + + have_integer = 0; } else + { T1_Skip_PS_Token( parser ); + have_integer = 0; + } T1_Skip_Spaces( parser ); } @@ -1732,7 +1774,7 @@ #endif if ( !loader.charstrings.init ) { - FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" )); + FT_ERROR(( "T1_Open_Face: no `/CharStrings' array in face!\n" )); error = T1_Err_Invalid_File_Format; }