ref: f546bacdcfcadd13c3b93332635530e58fc62ce3
parent: 5972e9abf82ba20c29215c3f8d9c75efa12ca243
author: David Turner <[email protected]>
date: Sun Feb 1 11:59:06 EST 2004
* 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 * 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 as hell. Aargh..
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2004-02-01 David Turner <[email protected]>
+
+ * 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
+
+ * 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 as hell.
+ Aargh..
+
2004-01-31 Werner Lemberg <[email protected]>
* src/cff/cffgload.c (cff_operator_seac): Fix magnitude of
--- a/Jamfile
+++ b/Jamfile
@@ -147,7 +147,7 @@
actions RefDoc
{
- python $(FT2_SRC)/tools/docmaker/docmaker.py --prefix=ft2 --title=FreeType-2.1.5 --output=$(DOC_DIR) $(FT2_INCLUDE)/freetype/*.h $(FT2_INCLUDE)/freetype/config/*.h $(FT2_INCLUDE)/freetype/cache/*.h
+ python $(FT2_SRC)/tools/docmaker/docmaker.py --prefix=ft2 --title=FreeType-2.1.8 --output=$(DOC_DIR) $(FT2_INCLUDE)/freetype/*.h $(FT2_INCLUDE)/freetype/config/*.h $(FT2_INCLUDE)/freetype/cache/*.h
}
RefDoc refdoc ;
--- a/include/freetype/cache/ftccache.h
+++ b/include/freetype/cache/ftccache.h
@@ -1,261 +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 );
-
-
-
-#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
-
-
- /* */
-
-FT_END_HEADER
-
-
-#endif /* __FTCCACHE_H__ */
-
-
-/* END */
+/***************************************************************************/
+/* */
+/* 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 */
--- a/include/freetype/cache/ftcglyph.h
+++ b/include/freetype/cache/ftcglyph.h
@@ -1,296 +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 );
-
-
-#define FTC_GCACHE_LOOKUP_CMP( cache, famcmp, nodecmp, hash, \
- gindex, query, node, error ) \
- FT_BEGIN_STMNT \
- FTC_GCache _gcache = FTC_GCACHE( cache ); \
- FTC_Family _family; \
- FTC_GQuery _gquery = (FTC_GQuery)( query ); \
- FTC_MruNode_CompareFunc _fcompare = (FTC_MruNode_CompareFunc)(famcmp); \
- \
- \
- _gquery->gindex = (gindex); \
- \
- FTC_MRULIST_LOOP( &_gcache->families, _family ) \
- { \
- if ( _fcompare( (FTC_MruNode)_family, _gquery ) ) \
- { \
- _gquery->family = _family; \
- goto _FamilyFound; \
- } \
- } \
- FTC_MRULIST_LOOP_END(); \
- \
- error = FTC_MruList_New( &_gcache->families, \
- _gquery, \
- (FTC_MruNode*)&_gquery->family ); \
- if ( !error ) \
- { \
- _FamilyFound: \
- FTC_CACHE_LOOKUP_CMP( cache, nodecmp, hash, query, node, error ); \
- } \
- FT_END_STMNT
- /* */
-
-FT_END_HEADER
-
-
-#endif /* __FTCGLYPH_H__ */
-
-
-/* END */
+/***************************************************************************/
+/* */
+/* 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 */
--- a/include/freetype/cache/ftcmru.h
+++ b/include/freetype/cache/ftcmru.h
@@ -1,239 +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( list, key, node, error ) \
- FT_BEGIN_STMNT \
- FTC_MruNode_CompareFunc _compare = (list)->clazz.node_compare; \
- FTC_MruNode _first, _node; \
- \
- \
- error = 0; \
- _first = (list)->nodes; \
- _node = NULL; \
- \
- if ( _first ) \
- { \
- _node = _first; \
- do \
- { \
- if ( _compare( _node, (key) ) ) \
- { \
- *(FTC_MruNode*)&(node) = _node; \
- goto _Ok; \
- } \
- _node = _node->next; \
- \
- } while ( _node != _first) ; \
- } \
- \
- error = FTC_MruList_New( (list), (key), (FTC_MruNode*)&(node) ); \
- _Ok: \
- ; \
- FT_END_STMNT
-
-#else /* !FTC_INLINE */
-
-#define FTC_MRULIST_LOOKUP_CMP( 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 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/Jamfile
+++ b/src/autofit/Jamfile
@@ -1,11 +1,11 @@
-SubDir FT2_TOP src autofit ;
-
+SubDir FT2_TOP src autofit ;
+
{
local _sources ;
if $(FT2_MULTI)
{
- _sources = afangles afglobal afhints aflatin ;
+ _sources = afangles afglobal afhints aflatin afloader afmodule ;
}
else
{
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -1,938 +1,938 @@
-#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; points++ )
- {
- 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/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -374,12 +374,28 @@
axis = & metrics->axis[ dim ];
- if ( axis->scale == scale && axis->delta == delta )
+ if ( axis->org_scale == scale && axis->org_delta == delta )
return;
+ axis->org_scale = scale;
+ axis->org_delta = delta;
+
+ /* XXX: TODO: Correct Y and X scale according to Chester rules
+ */
axis->scale = scale;
axis->delta = delta;
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ metrics->scaler.x_scale = scale;
+ metrics->scaler.x_delta = delta;
+ }
+ else
+ {
+ metrics->scaler.y_scale = scale;
+ metrics->scaler.y_delta = delta;
+ }
+
/* scale the standard widths
*/
for ( nn = 0; nn < axis->width_count; nn++ )
@@ -419,6 +435,8 @@
af_latin_metrics_scale( AF_LatinMetrics metrics,
AF_Scaler scaler )
{
+ metrics->scaler = scaler[0];
+
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
}
@@ -1120,7 +1138,6 @@
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
- AF_Scaler scaler,
FT_Outline* outline,
AF_LatinMetrics metrics )
{
@@ -1127,7 +1144,7 @@
FT_Error error;
FT_Render_Mode mode;
- error = af_glyph_hints_reset( hints, scaler, outline );
+ error = af_glyph_hints_reset( hints, &metrics->scaler, outline );
if (error)
goto Exit;
@@ -1135,7 +1152,7 @@
/* compute flags depending on render mode, etc...
*/
- mode = scaler->render_mode;
+ mode = metrics->scaler.render_mode;
/* we snap the width of vertical stems for the monochrome and
* horizontal LCD rendering targets only.
@@ -1716,12 +1733,10 @@
static FT_Error
af_latin_hints_apply( AF_GlyphHints hints,
- AF_Scaler scaler,
AF_LatinMetrics metrics )
{
AF_Dimension dim;
- FT_UNUSED( scaler );
FT_UNUSED( metrics );
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -81,6 +81,9 @@
FT_UInt blue_count;
AF_LatinBlueRec blues[ AF_LATIN_BLUE_MAX ];
+ FT_Fixed org_scale;
+ FT_Pos org_delta;
+
} AF_LatinAxisRec, *AF_LatinAxis;
@@ -89,6 +92,7 @@
AF_ScriptMetricsRec root;
FT_UInt units_per_em;
AF_LatinAxisRec axis[ AF_DIMENSION_MAX ];
+ AF_ScalerRec scaler;
} AF_LatinMetricsRec, *AF_LatinMetrics;
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -1,505 +1,431 @@
-#include "afloader.h"
-#include "afhints.h"
-#include "afglobal.h"
-#include "aflatin.h"
-
- FT_LOCAL_DEF( void )
- af_loader_init( AF_Loader loader,
- FT_Memory memory )
- {
- FT_ZERO( loader );
-
- af_glyph_hints_init( &loader->hints, memory );
- }
-
-
- FT_LOCAL_DEF( FT_Error )
- af_loader_reset( AF_Loader loader,
- FT_Face face )
- {
- FT_Error error = 0;
-
- FT_ZERO( loader );
-
- loader->face = face;
- loader->gloader = face->slot->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 = face;
- loader->globals = NULL;
- loader->gloader = NULL;
- }
-
-
- static FT_Error
- af_hinter_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, scaler,
- &gloader->current.outline,
- metrics );
- if ( error )
- goto Exit;
-
- /* apply the hints */
- error = metrics->clazz->script_hints_apply( hints, scaler,
- &gloader->current.outline,
- metrics );
- if ( error )
- goto Exit;
-
- /* 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_Edge edge1 = outline->vert_edges; /* leftmost edge */
- AF_Edge edge2 = edge1 +
- outline->num_vedges - 1; /* rightmost edge */
-
-
- old_advance = hinter->pp2.x;
- old_rsb = old_advance - edge2->opos;
- old_lsb = edge1->opos;
- new_lsb = edge1->pos;
-
- hinter->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb );
- hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb );
-
-#if 0
- /* try to fix certain bad advance computations */
- if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
- hinter->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 = hinter->pp1;
- pp2 = hinter->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 = hinter->pp1;
- pp2 = hinter->pp2;
- }
- else
- {
- hinter->pp1 = pp1;
- hinter->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 = AF_Err_Unimplemented_Feature;
- }
-
- Hint_Metrics:
- if ( depth == 0 )
- {
- FT_BBox bbox;
-
-
- /* transform the hinted outline if needed */
- if ( hinter->transformed )
- FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
-
- /* we must translate our final outline by -pp1.x and compute */
- /* the new metrics */
- if ( hinter->pp1.x )
- FT_Outline_Translate( &gloader->base.outline, -hinter->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 ( !FT_IS_FIXED_WIDTH( slot->face ) )
- slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
- else
- slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
- x_scale );
-
- slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
-
- /* now copy outline into glyph slot */
- af_loader_rewind( slot->internal->loader );
- error = af_loader_copy_points( slot->internal->loader, 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;
- }
-
-
-
-
-
- /* load and hint a given glyph */
- FT_LOCAL_DEF( FT_Error )
- af_loader_load_g( AF_Hinter hinter,
- FT_GlyphSlot slot,
- FT_Size size,
- FT_UInt glyph_index,
- FT_Int32 load_flags )
- {
- FT_Face face = slot->face;
- FT_Error error;
- FT_Fixed x_scale = size->metrics.x_scale;
- FT_Fixed y_scale = size->metrics.y_scale;
- AF_Face_Globals face_globals = FACE_GLOBALS( face );
- FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags );
-
-
- /* first of all, we need to check that we're using the correct face and */
- /* global hints to load the glyph */
- if ( hinter->face != face || hinter->globals != face_globals )
- {
- hinter->face = face;
- if ( !face_globals )
- {
- error = af_hinter_new_face_globals( hinter, face, 0 );
- if ( error )
- goto Exit;
-
- }
- hinter->globals = FACE_GLOBALS( face );
- face_globals = FACE_GLOBALS( face );
-
- }
-
-#ifdef FT_CONFIG_CHESTER_BLUE_SCALE
-
- /* try to optimize the y_scale so that the top of non-capital letters
- * is aligned on a pixel boundary whenever possible
- */
- {
- AF_Globals design = &face_globals->design;
- FT_Pos shoot = design->blue_shoots[AF_BLUE_SMALL_TOP];
-
-
- /* the value of 'shoot' will be -1000 if the font doesn't have */
- /* small latin letters; we simply check the sign here... */
- if ( shoot > 0 )
- {
- FT_Pos scaled = FT_MulFix( shoot, y_scale );
- FT_Pos fitted = FT_PIX_ROUND( scaled );
-
-
- if ( scaled != fitted )
- {
- /* adjust y_scale
- */
- y_scale = FT_MulDiv( y_scale, fitted, scaled );
-
- /* adust x_scale
- */
- if ( fitted < scaled )
- x_scale -= x_scale / 50; /* x_scale*0.98 with integers */
- }
- }
- }
-
-#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
-
- /* now, we must check the current character pixel size to see if we */
- /* need to rescale the global metrics */
- if ( face_globals->x_scale != x_scale ||
- face_globals->y_scale != y_scale )
- af_hinter_scale_globals( hinter, x_scale, y_scale );
-
- af_loader_rewind( hinter->loader );
-
- /* reset hinting flags according to load flags and current render target */
- hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
- hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
-
-#ifdef DEBUG_HINTER
- hinter->do_horz_hints = !af_debug_disable_vert; /* not a bug, the meaning */
- hinter->do_vert_hints = !af_debug_disable_horz; /* of h/v is inverted! */
-#endif
-
- /* we snap the width of vertical stems for the monochrome and */
- /* horizontal LCD rendering targets only. Corresponds to X snapping. */
- hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD );
-
- /* we snap the width of horizontal stems for the monochrome and */
- /* vertical LCD rendering targets only. Corresponds to Y snapping. */
- hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD_V );
-
- hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
-
- load_flags |= FT_LOAD_NO_SCALE
- | FT_LOAD_IGNORE_TRANSFORM;
- load_flags &= ~FT_LOAD_RENDER;
-
- error = af_hinter_load( hinter, glyph_index, load_flags, 0 );
-
- Exit:
- return error;
- }
-
-
- static FT_Error
- af_loader_load_glyph( AF_Loader loader,
- AF_Scaler scaler,
- FT_UInt glyph_index )
- {
- FT_Error error;
- FT_Face face = scaler->face;
-
- error = af_loader_reset( loader, face );
- if ( !error )
- {
- AF_ScriptMetrics metrics;
-
- error = af_face_globals_get_metrics( globals, gindex, &metrics );
- if ( !error )
- {
- metrics->clazz->script_metrics_scale( metrics, scaler );
-
- error = af_loader_load_g( loader, scaler, metrics, glyph_index,
- /* 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
@@ -21,22 +21,26 @@
} AF_LoaderRec, *AF_Loader;
- FT_LOCAL( void )
+
+ 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 );
+ af_loader_reset( AF_Loader loader,
+ FT_Face face );
+
FT_LOCAL( void )
- af_loader_done( AF_Loader loader );
+ af_loader_done( AF_Loader loader );
+
FT_LOCAL( FT_Error )
- af_loader_load_glyph( AF_Loader loader,
- FT_UInt gindex,
- FT_UInt32 load_flags,
- FT_UInt depth );
+ af_loader_load_glyph( AF_Loader loader,
+ FT_Face face,
+ FT_UInt gindex,
+ FT_UInt32 load_flags );
/* */
--- a/src/autofit/afmodule.c
+++ b/src/autofit/afmodule.c
@@ -1,437 +1,68 @@
#include "afmodule.h"
-#include "afhints.h"
-#include "afglobal.h"
-#include "aflatin.h"
+#include "afloader.h"
+#include FT_INTERNAL_OBJECTS_H
- static FT_Error
- af_hinter_load( AF_Hinter hinter,
- FT_UInt glyph_index,
- FT_Int32 load_flags,
- FT_UInt depth )
+ typedef struct FT_AutofitterRec_
{
- FT_Face face = hinter->face;
- FT_GlyphSlot slot = face->glyph;
- FT_Slot_Internal internal = slot->internal;
- FT_Fixed x_scale = hinter->globals->x_scale;
- FT_Fixed y_scale = hinter->globals->y_scale;
- FT_Error error;
- AF_Outline outline = hinter->glyph;
- AF_Loader gloader = hinter->loader;
+ FT_ModuleRec root;
+ AF_LoaderRec loader[1];
+ } FT_AutofitterRec, *FT_Autofitter;
- /* load the glyph */
- error = FT_Load_Glyph( face, glyph_index, load_flags );
- if ( error )
- goto Exit;
- /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
- hinter->transformed = internal->glyph_transformed;
+ FT_CALLBACK_DEF( FT_Error )
+ af_autofitter_init( FT_Autofitter module )
+ {
+ return af_loader_init( module->loader, module->root.library->memory );
+ }
- if ( hinter->transformed )
- {
- FT_Matrix imatrix;
-
- imatrix = internal->glyph_matrix;
- hinter->trans_delta = internal->glyph_delta;
- hinter->trans_matrix = imatrix;
-
- FT_Matrix_Invert( &imatrix );
- FT_Vector_Transform( &hinter->trans_delta, &imatrix );
- }
-
- /* set linear horizontal metrics */
- slot->linearHoriAdvance = slot->metrics.horiAdvance;
- slot->linearVertAdvance = slot->metrics.vertAdvance;
-
- switch ( slot->format )
- {
- case FT_GLYPH_FORMAT_OUTLINE:
-
- /* translate glyph outline if we need to */
- if ( hinter->transformed )
- {
- FT_UInt n = slot->outline.n_points;
- FT_Vector* point = slot->outline.points;
-
-
- for ( ; n > 0; point++, n-- )
- {
- point->x += hinter->trans_delta.x;
- point->y += hinter->trans_delta.y;
- }
- }
-
- /* copy the outline points in the loader's current */
- /* extra points which is used to keep original glyph coordinates */
- error = af_loader_check_points( 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 */
- hinter->pp1.x = 0;
- hinter->pp1.y = 0;
- hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
- hinter->pp2.y = 0;
-
- /* 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 = af_outline_load( outline, x_scale, y_scale, face );
- if ( error )
- goto Exit;
-
- /* perform feature detection */
- af_outline_detect_features( outline );
-
- if ( hinter->do_vert_hints )
- {
- af_outline_compute_blue_edges( outline, hinter->globals );
- af_outline_scale_blue_edges( outline, hinter->globals );
- }
-
- /* perform alignment control */
- af_hinter_hint_edges( hinter );
- af_hinter_align( hinter );
-
- /* now save the current outline into the loader's current table */
- af_outline_save( outline, gloader );
-
- /* 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_Edge edge1 = outline->vert_edges; /* leftmost edge */
- AF_Edge edge2 = edge1 +
- outline->num_vedges - 1; /* rightmost edge */
-
-
- old_advance = hinter->pp2.x;
- old_rsb = old_advance - edge2->opos;
- old_lsb = edge1->opos;
- new_lsb = edge1->pos;
-
- hinter->pp1.x = FT_PIX_ROUND( new_lsb - old_lsb );
- hinter->pp2.x = FT_PIX_ROUND( edge2->pos + old_rsb );
-
-#if 0
- /* try to fix certain bad advance computations */
- if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
- hinter->pp2.x += 64;
-#endif
- }
-
- /* good, we simply add the glyph to our loader's base */
- af_loader_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 = af_loader_check_subglyphs( 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 = hinter->pp1;
- pp2 = hinter->pp2;
-
- num_base_points = gloader->base.outline.n_points;
-
- error = af_hinter_load( hinter, 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 = hinter->pp1;
- pp2 = hinter->pp2;
- }
- else
- {
- hinter->pp1 = pp1;
- hinter->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 = AF_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, x_scale );
- y = FT_MulFix( subglyph->arg2, y_scale );
-
- 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 = AF_Err_Unimplemented_Feature;
- }
-
- Hint_Metrics:
- if ( depth == 0 )
- {
- FT_BBox bbox;
-
-
- /* transform the hinted outline if needed */
- if ( hinter->transformed )
- FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
-
- /* we must translate our final outline by -pp1.x and compute */
- /* the new metrics */
- if ( hinter->pp1.x )
- FT_Outline_Translate( &gloader->base.outline, -hinter->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 ( !FT_IS_FIXED_WIDTH( slot->face ) )
- slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
- else
- slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
- x_scale );
-
- slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
-
- /* now copy outline into glyph slot */
- af_loader_rewind( slot->internal->loader );
- error = af_loader_copy_points( slot->internal->loader, 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_CALLBACK_DEF( void )
+ af_autofitter_done( FT_Autofitter module )
+ {
+ af_loader_done( module->loader );
}
- /* load and hint a given glyph */
- FT_LOCAL_DEF( FT_Error )
- af_hinter_load_glyph( AF_Hinter hinter,
- FT_GlyphSlot slot,
- FT_Size size,
- FT_UInt glyph_index,
- FT_Int32 load_flags )
+ FT_CALLBACK_DEF( FT_Error )
+ af_autofitter_load_glyph( FT_Autofitter module,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
{
- FT_Face face = slot->face;
- FT_Error error;
- FT_Fixed x_scale = size->metrics.x_scale;
- FT_Fixed y_scale = size->metrics.y_scale;
- AF_Face_Globals face_globals = FACE_GLOBALS( face );
- FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE( load_flags );
+ return af_loader_load_glyph( module->loader, slot->face,
+ glyph_index, load_flags );
+ }
- /* first of all, we need to check that we're using the correct face and */
- /* global hints to load the glyph */
- if ( hinter->face != face || hinter->globals != face_globals )
- {
- hinter->face = face;
- if ( !face_globals )
- {
- error = af_hinter_new_face_globals( hinter, face, 0 );
- if ( error )
- goto Exit;
- }
- hinter->globals = FACE_GLOBALS( face );
- face_globals = FACE_GLOBALS( face );
+ FT_CALLBACK_TABLE_DEF
+ const FT_AutoHinter_ServiceRec af_autofitter_service =
+ {
+ NULL,
+ NULL,
+ NULL,
+ (FT_AutoHinter_GlyphLoadFunc) af_autofitter_load_glyph
+ };
- }
-#ifdef FT_CONFIG_CHESTER_BLUE_SCALE
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class autofit_module_class =
+ {
+ FT_MODULE_HINTER,
+ sizeof ( FT_AutofitterRec ),
- /* try to optimize the y_scale so that the top of non-capital letters
- * is aligned on a pixel boundary whenever possible
- */
- {
- AF_Globals design = &face_globals->design;
- FT_Pos shoot = design->blue_shoots[AF_BLUE_SMALL_TOP];
+ "autofitter",
+ 0x10000L, /* version 1.0 of the autofitter */
+ 0x20000L, /* requires FreeType 2.0 or above */
+ (const void*) &af_autofitter_service,
- /* the value of 'shoot' will be -1000 if the font doesn't have */
- /* small latin letters; we simply check the sign here... */
- if ( shoot > 0 )
- {
- FT_Pos scaled = FT_MulFix( shoot, y_scale );
- FT_Pos fitted = FT_PIX_ROUND( scaled );
+ (FT_Module_Constructor) af_autofitter_init,
+ (FT_Module_Destructor) af_autofitter_done,
+ (FT_Module_Requester) 0
+ };
- if ( scaled != fitted )
- {
- /* adjust y_scale
- */
- y_scale = FT_MulDiv( y_scale, fitted, scaled );
-
- /* adust x_scale
- */
- if ( fitted < scaled )
- x_scale -= x_scale / 50; /* x_scale*0.98 with integers */
- }
- }
- }
-
-#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
-
- /* now, we must check the current character pixel size to see if we */
- /* need to rescale the global metrics */
- if ( face_globals->x_scale != x_scale ||
- face_globals->y_scale != y_scale )
- af_hinter_scale_globals( hinter, x_scale, y_scale );
-
- af_loader_rewind( hinter->loader );
-
- /* reset hinting flags according to load flags and current render target */
- hinter->do_horz_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
- hinter->do_vert_hints = FT_BOOL( !(load_flags & FT_LOAD_NO_AUTOHINT) );
-
-#ifdef DEBUG_HINTER
- hinter->do_horz_hints = !af_debug_disable_vert; /* not a bug, the meaning */
- hinter->do_vert_hints = !af_debug_disable_horz; /* of h/v is inverted! */
-#endif
-
- /* we snap the width of vertical stems for the monochrome and */
- /* horizontal LCD rendering targets only. Corresponds to X snapping. */
- hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD );
-
- /* we snap the width of horizontal stems for the monochrome and */
- /* vertical LCD rendering targets only. Corresponds to Y snapping. */
- hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD_V );
-
- hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
-
- load_flags |= FT_LOAD_NO_SCALE
- | FT_LOAD_IGNORE_TRANSFORM;
- load_flags &= ~FT_LOAD_RENDER;
-
- error = af_hinter_load( hinter, glyph_index, load_flags, 0 );
-
- Exit:
- return error;
- }
+/* END */
--- a/src/autofit/afmodule.h
+++ b/src/autofit/afmodule.h
@@ -1,5 +1,17 @@
#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/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -226,12 +226,10 @@
typedef FT_Error (*AF_Script_InitHintsFunc)( AF_GlyphHints hints,
- AF_Scaler scaler,
FT_Outline* outline,
AF_ScriptMetrics metrics );
typedef void (*AF_Script_ApplyHintsFunc)( AF_GlyphHints hints,
- AF_Scaler scaler,
FT_Outline* outline,
AF_ScriptMetrics metrics );
--- a/src/autofit/autofit.c
+++ b/src/autofit/autofit.c
@@ -1,7 +1,10 @@
-#define FT_MAKE_OPTION_SINGLE_OBJECT
-
-#include <ft2build.h>
+#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 autohint_module_class =
+ const FT_Module_Class autofit_module_class =
{
FT_MODULE_HINTER,
sizeof ( FT_AutoHinterRec ),
--- a/src/cache/Jamfile
+++ b/src/cache/Jamfile
@@ -14,14 +14,14 @@
if $(FT2_MULTI)
{
- _sources = ftmru
- ftcmanag
- ftccache
- ftcglyph
- ftcsbits
+ _sources = ftcmru
+ ftcmanag
+ ftccache
+ ftcglyph
+ ftcsbits
ftcimage
- ftcbasic
- ftccmap
+ ftcbasic
+ ftccmap
;
}
else
--- a/src/cache/descrip.mms
+++ b/src/cache/descrip.mms
@@ -20,7 +20,6 @@
all : $(OBJS)
library [--.lib]freetype.olb $(OBJS)
-ftcache.obj : ftcache.c ftcmru.c ftcmanag.c ftccache.c ftcglyph.c ftcimage.c \
- ftcsbits.c ftccmap.c ftcbasic.c
+ftcache.obj : ftcache.c
# EOF
--- a/src/cache/ftcbasic.c
+++ b/src/cache/ftcbasic.c
@@ -269,9 +269,12 @@
query.attrs.scaler.pixel = 1;
query.attrs.load_flags = type->flags;
+ query.attrs.scaler.x_res = 0; /* make compilers happy */
+ query.attrs.scaler.y_res = 0;
+
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
-
-#if 1 /* inlining is about 50% faster! */
+
+#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
FTC_GNode_Compare,
@@ -376,11 +379,14 @@
query.attrs.scaler.pixel = 1;
query.attrs.load_flags = type->flags;
+ query.attrs.scaler.x_res = 0; /* make compilers happy */
+ query.attrs.scaler.y_res = 0;
+
/* beware, the hash must be the same for all glyph ranges! */
hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
gindex / FTC_SBIT_ITEMS_PER_NODE;
-#if 1 /* inlining is about 50% faster! */
+#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
FTC_SNode_Compare,
@@ -394,7 +400,7 @@
gindex,
FTC_GQUERY( &query ),
(FTC_Node*)&node );
-#endif
+#endif
if ( error )
goto Exit;
--- a/src/cache/ftccmap.c
+++ b/src/cache/ftccmap.c
@@ -240,7 +240,7 @@
node, error );
#else
error = FTC_Cache_Lookup( cache, hash, &query, (FTC_Node*) &node );
-#endif
+#endif
if ( error )
goto Exit;
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -165,22 +165,15 @@
if ( !manager )
return FTC_Err_Invalid_Cache_Handle;
- /* we break encapsulation for the sake of speed */
+#ifdef FTC_INLINE
- error = 0;
- FTC_MRULIST_LOOP( &manager->sizes, node )
- {
- FTC_Scaler scaler0 = &node->scaler;
+ FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
+ node, error );
+#else
+ error = FTC_MruList_Lookup( &manager->sizes, scaler, (FTC_MruNode*)&node );
+#endif
- if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
- goto Found;
- }
- FTC_MRULIST_LOOP_END();
-
- error = FTC_MruList_New( &manager->sizes, scaler, (FTC_MruNode*)&node );
-
- Found:
if ( !error )
*asize = node->size;
@@ -287,18 +280,15 @@
return FTC_Err_Invalid_Cache_Handle;
/* we break encapsulation for the sake of speed */
+#ifdef FTC_INLINE
- error = 0;
- FTC_MRULIST_LOOP( &manager->faces, node )
- {
- if ( node->face_id == face_id )
- goto Found;
- }
- FTC_MRULIST_LOOP_END();
+ FTC_MRULIST_LOOKUP_CMP( &manager->faces, face_id, ftc_face_node_compare,
+ node, error );
- error = FTC_MruList_New( &manager->faces, face_id, (FTC_MruNode*)&node );
+#else
+ error = FTC_MruList_Lookup( &manager->faces, face_id, (FTC_MruNode*)&node );
+#endif
- Found:
if ( !error )
*aface = node->face;
--- a/src/cache/ftcmru.c
+++ b/src/cache/ftcmru.c
@@ -215,10 +215,15 @@
do
{
if ( compare( node, key ) )
+ {
+ if ( node != first )
+ FTC_MruNode_Up( &list->nodes, node );
+
return node;
+ }
node = node->next;
-
+
} while ( node != first);
}
--- a/src/sfnt/Jamfile
+++ b/src/sfnt/Jamfile
@@ -8,7 +8,7 @@
if $(FT2_MULTI)
{
- _sources = sfobjs sfdriver ttcmap ttcmap0 ttpost ttload ttsbit ;
+ _sources = sfobjs sfdriver ttcmap0 ttpost ttload ttsbit ;
}
else
{