ref: 6b3d00e1a0bc5033aeeab51912eda0aff6ed6e8b
parent: cf7d908c48007c4340aeee787e58e4002727973b
author: Werner Lemberg <[email protected]>
date: Tue Feb 3 16:34:29 EST 2004
* 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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2003-02-02 Werner Lemberg <[email protected]>
+
+ * 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 <[email protected]>
* 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 <[email protected]>
--- a/Jamfile
+++ b/Jamfile
@@ -1,4 +1,4 @@
-# FreeType 2 top Jamfile (c) 2001, 2002, 2003 David Turner
+# FreeType 2 top Jamfile (c) 2001, 2002, 2003, 2004 David Turner
#
# The HDRMACRO is already defined in FTJam and is used to add
--- 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 */
--- 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 */
--- 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 */
--- 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;
+ }
+ }
--- 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;
+ }
--- 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__ */
--- 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__ */
--- 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"
--- 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 ),
--- 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 ;
--- 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,
--- 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, */
--- 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, */
--- 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, */
--- 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 ;
--- 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;
}