summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--Jamfile2
-rw-r--r--include/freetype/cache/ftccache.h532
-rw-r--r--include/freetype/cache/ftcglyph.h593
-rw-r--r--include/freetype/cache/ftcmru.h485
-rw-r--r--src/autofit/Jamfile6
-rw-r--r--src/autofit/afhints.c1876
-rw-r--r--src/autofit/aflatin.c27
-rw-r--r--src/autofit/aflatin.h4
-rw-r--r--src/autofit/afloader.c936
-rw-r--r--src/autofit/afloader.h20
-rw-r--r--src/autofit/afmodule.c461
-rw-r--r--src/autofit/afmodule.h12
-rw-r--r--src/autofit/aftypes.h2
-rw-r--r--src/autofit/autofit.c9
-rw-r--r--src/autohint/ahmodule.c2
-rw-r--r--src/cache/Jamfile14
-rw-r--r--src/cache/descrip.mms3
-rw-r--r--src/cache/ftcbasic.c14
-rw-r--r--src/cache/ftccmap.c2
-rw-r--r--src/cache/ftcmanag.c34
-rw-r--r--src/cache/ftcmru.c7
-rw-r--r--src/sfnt/Jamfile2
23 files changed, 2343 insertions, 2716 deletions
diff --git a/ChangeLog b/ChangeLog
index 42fd661fe..fb6b505b1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2004-02-01 David Turner <david@freetype.org>
+
+ * 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 <wl@gnu.org>
* src/cff/cffgload.c (cff_operator_seac): Fix magnitude of
diff --git a/Jamfile b/Jamfile
index 11443f181..3f827d1c5 100644
--- a/Jamfile
+++ b/Jamfile
@@ -147,7 +147,7 @@ if $(DEBUG_HINTER)
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 ;
diff --git a/include/freetype/cache/ftccache.h b/include/freetype/cache/ftccache.h
index 98db284c8..9379d7fe6 100644
--- 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 */
diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h
index 866fab5ad..00f9cee55 100644
--- 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 */
diff --git a/include/freetype/cache/ftcmru.h b/include/freetype/cache/ftcmru.h
index cd2a654c7..d2bac3a87 100644
--- 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 */
diff --git a/src/autofit/Jamfile b/src/autofit/Jamfile
index a5a6445f5..3253c821e 100644
--- 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
{
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index 9645cf796..ef6410d47 100644
--- 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;
+ }
+ }
+
+
+
+
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 2fd7236bf..0ddc562ac 100644
--- 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,14 +1138,13 @@
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
- AF_Scaler scaler,
FT_Outline* outline,
AF_LatinMetrics metrics )
{
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++ )
diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h
index c3476c564..da51cad69 100644
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -81,6 +81,9 @@ FT_BEGIN_HEADER
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 @@ FT_BEGIN_HEADER
AF_ScriptMetricsRec root;
FT_UInt units_per_em;
AF_LatinAxisRec axis[ AF_DIMENSION_MAX ];
+ AF_ScalerRec scaler;
} AF_LatinMetricsRec, *AF_LatinMetrics;
diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index e2b5260f9..69738dd88 100644
--- 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;
+ }
diff --git a/src/autofit/afloader.h b/src/autofit/afloader.h
index 8385035e4..7bff19239 100644
--- a/src/autofit/afloader.h
+++ b/src/autofit/afloader.h
@@ -21,22 +21,26 @@ FT_BEGIN_HEADER
} 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 );
/* */
diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c
index 811ec3b8e..d088c24ae 100644
--- 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;
-
- 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( FT_Error )
+ af_autofitter_init( FT_Autofitter module )
+ {
+ return af_loader_init( module->loader, module->root.library->memory );
}
- /* 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( void )
+ af_autofitter_done( FT_Autofitter module )
{
- 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 );
+ af_loader_done( module->loader );
+ }
- /* adust x_scale
- */
- if ( fitted < scaled )
- x_scale -= x_scale / 50; /* x_scale*0.98 with integers */
- }
- }
- }
-#endif /* FT_CONFIG_CHESTER_BLUE_SCALE */
+ 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 )
+ {
+ return af_loader_load_glyph( module->loader, slot->face,
+ glyph_index, load_flags );
+ }
- /* 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) );
+ FT_CALLBACK_TABLE_DEF
+ const FT_AutoHinter_ServiceRec af_autofitter_service =
+ {
+ NULL,
+ NULL,
+ NULL,
+ (FT_AutoHinter_GlyphLoadFunc) af_autofitter_load_glyph
+ };
-#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 );
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class autofit_module_class =
+ {
+ FT_MODULE_HINTER,
+ sizeof ( FT_AutofitterRec ),
- /* 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 );
+ "autofitter",
+ 0x10000L, /* version 1.0 of the autofitter */
+ 0x20000L, /* requires FreeType 2.0 or above */
- hinter->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
+ (const void*) &af_autofitter_service,
- load_flags |= FT_LOAD_NO_SCALE
- | FT_LOAD_IGNORE_TRANSFORM;
- load_flags &= ~FT_LOAD_RENDER;
+ (FT_Module_Constructor) af_autofitter_init,
+ (FT_Module_Destructor) af_autofitter_done,
+ (FT_Module_Requester) 0
+ };
- error = af_hinter_load( hinter, glyph_index, load_flags, 0 );
- Exit:
- return error;
- }
+/* END */
diff --git a/src/autofit/afmodule.h b/src/autofit/afmodule.h
index cf7e05bfe..fec4f2075 100644
--- 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__ */
diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h
index f34771e99..3f968fc33 100644
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -226,12 +226,10 @@ FT_BEGIN_HEADER
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 );
diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c
index b8b1c506b..ad7084fdd 100644
--- 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"
+
+
diff --git a/src/autohint/ahmodule.c b/src/autohint/ahmodule.c
index 8fce31d61..336fdcbeb 100644
--- 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 ),
diff --git a/src/cache/Jamfile b/src/cache/Jamfile
index baa1d7761..3b64863ec 100644
--- a/src/cache/Jamfile
+++ b/src/cache/Jamfile
@@ -14,14 +14,14 @@ HDRMACRO [ FT2_SubDir include ftcache.h ] ;
if $(FT2_MULTI)
{
- _sources = ftmru
- ftcmanag
- ftccache
- ftcglyph
- ftcsbits
+ _sources = ftcmru
+ ftcmanag
+ ftccache
+ ftcglyph
+ ftcsbits
ftcimage
- ftcbasic
- ftccmap
+ ftcbasic
+ ftccmap
;
}
else
diff --git a/src/cache/descrip.mms b/src/cache/descrip.mms
index daa2d7deb..ee165798d 100644
--- a/src/cache/descrip.mms
+++ b/src/cache/descrip.mms
@@ -20,7 +20,6 @@ OBJS=ftcache.obj
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
diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c
index cf8c912dd..a989336e5 100644
--- 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;
diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c
index 0153763af..4861b797a 100644
--- 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;
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
index 73a9c04a5..6d60e4cf7 100644
--- 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 */
-
- error = 0;
- FTC_MRULIST_LOOP( &manager->sizes, node )
- {
- FTC_Scaler scaler0 = &node->scaler;
+#ifdef FTC_INLINE
+ FTC_MRULIST_LOOKUP_CMP( &manager->sizes, scaler, ftc_size_node_compare,
+ node, error );
- if ( FTC_SCALER_COMPARE( scaler0, scaler ) )
- goto Found;
- }
- FTC_MRULIST_LOOP_END();
-
- error = FTC_MruList_New( &manager->sizes, scaler, (FTC_MruNode*)&node );
+#else
+ error = FTC_MruList_Lookup( &manager->sizes, scaler, (FTC_MruNode*)&node );
+#endif
- 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;
diff --git a/src/cache/ftcmru.c b/src/cache/ftcmru.c
index af97ce31e..18df02074 100644
--- 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);
}
diff --git a/src/sfnt/Jamfile b/src/sfnt/Jamfile
index adddfb6fd..9727c0640 100644
--- a/src/sfnt/Jamfile
+++ b/src/sfnt/Jamfile
@@ -8,7 +8,7 @@ SubDir FT2_TOP $(FT2_SRC_DIR) sfnt ;
if $(FT2_MULTI)
{
- _sources = sfobjs sfdriver ttcmap ttcmap0 ttpost ttload ttsbit ;
+ _sources = sfobjs sfdriver ttcmap0 ttpost ttload ttsbit ;
}
else
{