diff options
author | Werner Lemberg <wl@gnu.org> | 2004-02-03 21:34:29 +0000 |
---|---|---|
committer | Werner Lemberg <wl@gnu.org> | 2004-02-03 21:34:29 +0000 |
commit | 781072441efbb671077a607b0cedc4a9d99e7fe6 (patch) | |
tree | bd5c6171935f1fdbd026b11fc4b97fe0583743b4 | |
parent | 64e6f5b5a756abb11a0f0583a9b99a99b6537c67 (diff) | |
download | freetype2-781072441efbb671077a607b0cedc4a9d99e7fe6.tar.gz |
* 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.
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | Jamfile | 2 | ||||
-rw-r--r-- | include/freetype/cache/ftccache.h | 542 | ||||
-rw-r--r-- | include/freetype/cache/ftcglyph.h | 594 | ||||
-rw-r--r-- | include/freetype/cache/ftcmru.h | 492 | ||||
-rw-r--r-- | src/autofit/afhints.c | 1872 | ||||
-rw-r--r-- | src/autofit/afloader.c | 862 | ||||
-rw-r--r-- | src/autofit/afloader.h | 99 | ||||
-rw-r--r-- | src/autofit/afmodule.h | 33 | ||||
-rw-r--r-- | src/autofit/autofit.c | 18 | ||||
-rw-r--r-- | src/autohint/ahmodule.c | 2 | ||||
-rw-r--r-- | src/cache/Jamfile | 2 | ||||
-rw-r--r-- | src/cache/descrip.mms | 2 | ||||
-rw-r--r-- | src/cache/ftcbasic.c | 2 | ||||
-rw-r--r-- | src/cache/ftccmap.c | 2 | ||||
-rw-r--r-- | src/cache/ftcmru.c | 2 | ||||
-rw-r--r-- | src/sfnt/Jamfile | 2 | ||||
-rw-r--r-- | src/type1/t1load.c | 62 |
18 files changed, 2336 insertions, 2282 deletions
@@ -1,3 +1,11 @@ +2003-02-02 Werner Lemberg <wl@gnu.org> + + * 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 <wl@gnu.org> * 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) + <FTC_INLINE>: Provide macro version which doesn't use inline code. + * include/freetype/cache/ftcglyph.h (FTC_GCACHE_LOOKUP_CMP) + <FTC_INLINE>: 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) <FTC_INLINE>: 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 <wl@gnu.org> @@ -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 <ft2build.h>
-#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 <ft2build.h> +#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 <ft2build.h>
-#include FT_FREETYPE_H
-
-#ifdef FREETYPE_H
-#error "freetype.h of FreeType 1 has been loaded!"
-#error "Please fix the directory search order for header files"
-#error "so that freetype.h of FreeType 2 is found first."
-#endif
-
-#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 <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + +#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 <stdio.h>
-
- 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 <stdio.h> + + 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 <ft2build.h>
-#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 <ft2build.h> +#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 <ft2build.h>
-#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 <ft2build.h> +#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; } |