autohint:

Formatting.

  Replacing many enums with #defines since we do arithmetics (especially
  ORing which would produce undefined enum values). The ideal thing instead
  of #defines is `const int' as provided in C++...

  Adding header files to rules.mk
This commit is contained in:
Werner Lemberg 2000-07-26 14:11:15 +00:00
parent d082cd6801
commit c3dd151b0f
14 changed files with 1546 additions and 1237 deletions

View File

@ -102,14 +102,14 @@
AH_LOG(( "blue zones computation\n" )); AH_LOG(( "blue zones computation\n" ));
AH_LOG(( "------------------------------------------------\n" )); AH_LOG(( "------------------------------------------------\n" ));
for ( blue = (AH_Blue)0; blue < ah_blue_max; blue++ ) for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
{ {
const char* p = blue_chars[blue]; const char* p = blue_chars[blue];
const char* limit = p + MAX_TEST_CHARACTERS; const char* limit = p + MAX_TEST_CHARACTERS;
FT_Pos *blue_ref, *blue_shoot; FT_Pos *blue_ref, *blue_shoot;
AH_LOG(( "blue %3d: ", (int)blue )); AH_LOG(( "blue %3d: ", blue ));
num_flats = 0; num_flats = 0;
num_rounds = 0; num_rounds = 0;

View File

@ -11,7 +11,7 @@
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
@ -547,7 +547,7 @@
/* a segment is round if either its first or last point */ /* a segment is round if either its first or last point */
/* is a control point */ /* is a control point */
if ( ( segment->first->flags | point->flags ) & if ( ( segment->first->flags | point->flags ) &
ah_flah_control ) ah_flah_control )
segment->flags |= ah_edge_round; segment->flags |= ah_edge_round;
/* compute segment size */ /* compute segment size */
@ -1150,7 +1150,7 @@
if ( best_dist > 64 / 4 ) if ( best_dist > 64 / 4 )
best_dist = 64 / 4; best_dist = 64 / 4;
for ( blue = (AH_Blue)0; blue < ah_blue_max; blue++ ) for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
{ {
/* if it is a top zone, check for right edges -- if it is a bottom */ /* if it is a top zone, check for right edges -- if it is a bottom */
/* zone, check for left edges */ /* zone, check for left edges */
@ -1213,79 +1213,87 @@
} }
/************************************************************************ /*************************************************************************/
* /* */
* <Function> /* <Function> */
* ah_outline_scale_blue_edges /* ah_outline_scale_blue_edges */
* /* */
* <Description> /* <Description> */
* This functions must be called before hinting in order to re-adjust /* This functions must be called before hinting in order to re-adjust */
* the content of the detected edges (basically change the "blue edge" /* the contents of the detected edges (basically change the `blue */
* pointer from 'design units' to 'scaled ones' /* edge' pointer from `design units' to `scaled ones'). */
* /* */
************************************************************************/
LOCAL_FUNC LOCAL_FUNC
void ah_outline_scale_blue_edges( AH_Outline* outline, void ah_outline_scale_blue_edges( AH_Outline* outline,
AH_Face_Globals* globals ) AH_Face_Globals* globals )
{ {
AH_Edge* edge = outline->horz_edges; AH_Edge* edge = outline->horz_edges;
AH_Edge* limit = edge + outline->num_hedges; AH_Edge* limit = edge + outline->num_hedges;
FT_Int delta; FT_Int delta;
delta = globals->scaled.blue_refs - globals->design.blue_refs; delta = globals->scaled.blue_refs - globals->design.blue_refs;
for ( ; edge < limit; edge++ ) for ( ; edge < limit; edge++ )
{ {
if (edge->blue_edge) if ( edge->blue_edge )
edge->blue_edge += delta; edge->blue_edge += delta;
} }
} }
#ifdef AH_DEBUG_GLYPH #ifdef AH_DEBUG_GLYPH
extern
void ah_dump_edges( AH_Outline* outline ) void ah_dump_edges( AH_Outline* outline )
{ {
AH_Edge* edges; AH_Edge* edges;
AH_Edge* limit; AH_Edge* limit;
AH_Segment* segments; AH_Segment* segments;
FT_Int dimension; FT_Int dimension;
edges = outline->horz_edges; edges = outline->horz_edges;
limit = edges + outline->num_hedges; limit = edges + outline->num_hedges;
segments = outline->horz_segments; segments = outline->horz_segments;
for ( dimension = 1; dimension >= 0; dimension-- ) for ( dimension = 1; dimension >= 0; dimension-- )
{ {
AH_Edge* edge; AH_Edge* edge;
printf ( "Table of %s edges:\n", !dimension ? "vertical" : "horizontal" );
printf ( " [ index | pos | dir | link | serif | blue | opos | pos ]\n" ); printf ( "Table of %s edges:\n",
!dimension ? "vertical" : "horizontal" );
printf ( " [ index | pos | dir | link |"
" serif | blue | opos | pos ]\n" );
for ( edge = edges; edge < limit; edge++ ) for ( edge = edges; edge < limit; edge++ )
{ {
printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
edge - edges, edge - edges,
(int)edge->fpos, (int)edge->fpos,
edge->dir == ah_dir_up ? "up" : edge->dir == ah_dir_up
(edge->dir == ah_dir_down ? "down" : ? "up"
(edge->dir == ah_dir_left ? "left" : : ( edge->dir == ah_dir_down
(edge->dir == ah_dir_right ? "right" : "none") ? "down"
) : ( edge->dir == ah_dir_left
), ? "left"
edge->link ? (edge->link-edges) : -1, : ( edge->dir == ah_dir_right
edge->serif ? (edge->serif-edges) : -1, ? "right"
: "none" ) ) ),
edge->link ? ( edge->link - edges ) : -1,
edge->serif ? ( edge->serif - edges ) : -1,
edge->blue_edge ? 'y' : 'n', edge->blue_edge ? 'y' : 'n',
edge->opos/64.0, edge->opos / 64.0,
edge->pos/64.0 ); edge->pos / 64.0 );
} }
edges = outline->vert_edges; edges = outline->vert_edges;
limit = edges + outline->num_vedges; limit = edges + outline->num_vedges;
segments = outline->vert_segments; segments = outline->vert_segments;
} }
} }
#endif
#endif /* AH_DEBUG_GLYPH */
/* END */

File diff suppressed because it is too large Load Diff

View File

@ -2,64 +2,71 @@
/* */ /* */
/* ahhint.h */ /* ahhint.h */
/* */ /* */
/* Glyph hinter declarations */ /* Glyph hinter (declaration). */
/* */ /* */
/* Copyright 2000: Catharon Productions Inc. */ /* Copyright 2000 Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#ifndef AGHINT_H
#define AGHINT_H
#ifndef AHHINT_H
#define AHHINT_H
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
#include "ahglobal.h" #include "ahglobal.h"
#else #else
#include <autohint/ahglobal.h> #include <autohint/ahglobal.h>
#endif #endif
#define AH_HINT_DEFAULT 0
#define AH_HINT_NO_ALIGNMENT 1 #define AH_HINT_DEFAULT 0
#define AH_HINT_NO_HORZ_EDGES 0x20000 #define AH_HINT_NO_ALIGNMENT 1
#define AH_HINT_NO_VERT_EDGES 0x40000 #define AH_HINT_NO_HORZ_EDGES 0x20000L
#define AH_HINT_NO_VERT_EDGES 0x40000L
/* create a new empty hinter object */
FT_Error ah_hinter_new( FT_Library library,
AH_Hinter** ahinter );
/* create a new empty hinter object */ /* Load a hinted glyph in the hinter */
extern
FT_Error ah_hinter_new( FT_Library library, AH_Hinter* *ahinter );
/* Load a hinted glyph in the hinter */
extern
FT_Error ah_hinter_load_glyph( AH_Hinter* hinter, FT_Error ah_hinter_load_glyph( AH_Hinter* hinter,
FT_GlyphSlot slot, FT_GlyphSlot slot,
FT_Size size, FT_Size size,
FT_UInt glyph_index, FT_UInt glyph_index,
FT_Int load_flags ); FT_Int load_flags );
/* finalise a hinter object */ /* finalize a hinter object */
extern void ah_hinter_done( AH_Hinter* hinter );
void ah_hinter_done( AH_Hinter* hinter );
LOCAL_DEF LOCAL_DEF
void ah_hinter_done_face_globals( AH_Face_Globals* globals ); void ah_hinter_done_face_globals( AH_Face_Globals* globals );
extern void ah_hinter_get_global_hints( AH_Hinter* hinter,
void ah_hinter_get_global_hints( AH_Hinter* hinter, FT_Face face,
FT_Face face, void** global_hints,
void* *global_hints, long* global_len );
long *global_len );
extern void ah_hinter_done_global_hints( AH_Hinter* hinter,
void ah_hinter_done_global_hints( AH_Hinter* hinter, void* global_hints );
void* global_hints );
#endif /* AGHINT_H */
#endif /* AHHINT_H */
/* END */

View File

@ -2,44 +2,53 @@
/* */ /* */
/* ahloader.h */ /* ahloader.h */
/* */ /* */
/* Glyph loader implementation for the auto-hinting module */ /* Glyph loader for the auto-hinting module (declaration only). */
/* This defines the AG_GlyphLoader type in two different ways: */
/* */ /* */
/* - when the module is compiled within FreeType 2, the type */ /* Copyright 2000 Catharon Productions Inc. */
/* is simply a typedef to FT_GlyphLoader */
/* */
/* - when the module is compiled as a standalone object, */
/* AG_GlyphLoader has its own implementation.. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#ifndef AGLOADER_H
#define AGLOADER_H
/*************************************************************************/
/* */
/* This defines the AH_GlyphLoader type in two different ways: */
/* */
/* - If the module is compiled within FreeType 2, the type is simply a */
/* typedef to FT_GlyphLoader. */
/* */
/* - If the module is compiled as a standalone object, AH_GlyphLoader */
/* has its own implementation. */
/* */
/*************************************************************************/
#ifndef AHLOADER_H
#define AHLOADER_H
#ifdef _STANDALONE_ #ifdef _STANDALONE_
typedef struct AH_GlyphLoad_ typedef struct AH_GlyphLoad_
{ {
FT_Outline outline; /* outline */ FT_Outline outline; /* outline */
FT_UInt num_subglyphs; /* number of subglyphs */ FT_UInt num_subglyphs; /* number of subglyphs */
FT_SubGlyph* subglyphs; /* subglyphs */ FT_SubGlyph* subglyphs; /* subglyphs */
FT_Vector* extra_points; /* extra points table.. */ FT_Vector* extra_points; /* extra points table */
} AH_GlyphLoad; } AH_GlyphLoad;
struct AH_GlyphLoader_ struct AH_GlyphLoader_
{ {
FT_Memory memory; FT_Memory memory;
FT_UInt max_points; FT_UInt max_points;
@ -50,38 +59,47 @@
AH_GlyphLoad base; AH_GlyphLoad base;
AH_GlyphLoad current; AH_GlyphLoad current;
void* other; /* for possible future extension ? */ void* other; /* for possible future extensions */
}; };
LOCAL_DEF FT_Error AH_GlyphLoader_New( FT_Memory memory, LOCAL_DEF
AH_GlyphLoader* *aloader ); FT_Error AH_GlyphLoader_New( FT_Memory memory,
AH_GlyphLoader** aloader );
LOCAL_DEF FT_Error AH_GlyphLoader_Create_Extra( AH_GlyphLoader* loader ); LOCAL_DEF
FT_Error AH_GlyphLoader_Create_Extra( AH_GlyphLoader* loader );
LOCAL_DEF void AH_GlyphLoader_Done( AH_GlyphLoader* loader ); LOCAL_DEF
void AH_GlyphLoader_Done( AH_GlyphLoader* loader );
LOCAL_DEF void AH_GlyphLoader_Reset( AH_GlyphLoader* loader ); LOCAL_DEF
void AH_GlyphLoader_Reset( AH_GlyphLoader* loader );
LOCAL_DEF void AH_GlyphLoader_Rewind( AH_GlyphLoader* loader ); LOCAL_DEF
void AH_GlyphLoader_Rewind( AH_GlyphLoader* loader );
LOCAL_DEF FT_Error AH_GlyphLoader_Check_Points( AH_GlyphLoader* loader, LOCAL_DEF
FT_UInt n_points, FT_Error AH_GlyphLoader_Check_Points( AH_GlyphLoader* loader,
FT_UInt n_contours ); FT_UInt n_points,
FT_UInt n_contours );
LOCAL_DEF FT_Error AH_GlyphLoader_Check_Subglyphs( AH_GlyphLoader* loader, LOCAL_DEF
FT_UInt n_subs ); FT_Error AH_GlyphLoader_Check_Subglyphs( AH_GlyphLoader* loader,
FT_UInt n_subs );
LOCAL_DEF void AH_GlyphLoader_Prepare( AH_GlyphLoader* loader ); LOCAL_DEF
void AH_GlyphLoader_Prepare( AH_GlyphLoader* loader );
LOCAL_DEF
void AH_GlyphLoader_Add( AH_GlyphLoader* loader );
LOCAL_DEF void AH_GlyphLoader_Add( AH_GlyphLoader* loader ); LOCAL_DEF
FT_Error AH_GlyphLoader_Copy_Points( AH_GlyphLoader* target,
FT_GlyphLoader* source );
LOCAL_DEF FT_Error AH_GlyphLoader_Copy_Points( AH_GlyphLoader* target, #else /* _STANDALONE */
FT_GlyphLoader* source );
#else
#include <freetype/internal/ftobjs.h> #include <freetype/internal/ftobjs.h>
#define AH_Load FT_GlyphLoad #define AH_Load FT_GlyphLoad
@ -98,6 +116,9 @@
#define ah_loader_add FT_GlyphLoader_Add #define ah_loader_add FT_GlyphLoader_Add
#define ah_loader_copy_points FT_GlyphLoader_Copy_Points #define ah_loader_copy_points FT_GlyphLoader_Copy_Points
#endif #endif /* _STANDALONE_ */
#endif /* AGLOADER_H */ #endif /* AHLOADER_H */
/* END */

View File

@ -2,34 +2,41 @@
/* */ /* */
/* ahmodule.c */ /* ahmodule.c */
/* */ /* */
/* Auto-hinting module implementation */ /* Auto-hinting module implementation (declaration). */
/* */ /* */
/* Copyright 2000: Catharon Productions Inc. */ /* Copyright 2000 Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#include <freetype/ftmodule.h> #include <freetype/ftmodule.h>
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
#include "ahhint.h" #include "ahhint.h"
#else #else
#include <autohint/ahhint.h> #include <autohint/ahhint.h>
#endif #endif
typedef struct FT_AutoHinterRec_ typedef struct FT_AutoHinterRec_
{ {
FT_ModuleRec root; FT_ModuleRec root;
AH_Hinter* hinter; AH_Hinter* hinter;
} FT_AutoHinterRec; } FT_AutoHinterRec;
@ -40,37 +47,42 @@
return ah_hinter_new( module->root.library, &module->hinter ); return ah_hinter_new( module->root.library, &module->hinter );
} }
static static
void ft_autohinter_done( FT_AutoHinter module ) void ft_autohinter_done( FT_AutoHinter module )
{ {
ah_hinter_done( module->hinter ); ah_hinter_done( module->hinter );
} }
static static
FT_Error ft_autohinter_load( FT_AutoHinter module, FT_Error ft_autohinter_load( FT_AutoHinter module,
FT_GlyphSlot slot, FT_GlyphSlot slot,
FT_Size size, FT_Size size,
FT_UInt glyph_index, FT_UInt glyph_index,
FT_ULong load_flags ) FT_ULong load_flags )
{ {
return ah_hinter_load_glyph( module->hinter, return ah_hinter_load_glyph( module->hinter,
slot, size, glyph_index, load_flags ); slot, size, glyph_index, load_flags );
} }
static static
void ft_autohinter_reset( FT_AutoHinter module, void ft_autohinter_reset( FT_AutoHinter module,
FT_Face face ) FT_Face face )
{ {
UNUSED(module); UNUSED( module );
if (face->autohint.data)
ah_hinter_done_face_globals( face->autohint.data ); if ( face->autohint.data )
ah_hinter_done_face_globals( (AH_Face_Globals*)(face->autohint.data) );
} }
static static
void ft_autohinter_get_globals( FT_AutoHinter module, void ft_autohinter_get_globals( FT_AutoHinter module,
FT_Face face, FT_Face face,
void* *global_hints, void** global_hints,
long *global_len ) long* global_len )
{ {
ah_hinter_get_global_hints( module->hinter, face, ah_hinter_get_global_hints( module->hinter, face,
global_hints, global_len ); global_hints, global_len );
@ -94,18 +106,22 @@
ft_autohinter_done_globals ft_autohinter_done_globals
}; };
const FT_Module_Class autohint_module_class = const FT_Module_Class autohint_module_class =
{ {
ft_module_hinter, ft_module_hinter,
sizeof( FT_AutoHinterRec ), sizeof ( FT_AutoHinterRec ),
"autohinter", "autohinter",
0x10000, /* version 1.0 of the autohinter */ 0x10000L, /* version 1.0 of the autohinter */
0x20000, /* requires FreeType 2.0 or above */ 0x20000L, /* requires FreeType 2.0 or above */
(const void*)&autohinter_interface, (const void*)&autohinter_interface,
(FT_Module_Constructor) ft_autohinter_init, (FT_Module_Constructor)ft_autohinter_init,
(FT_Module_Destructor) ft_autohinter_done, (FT_Module_Destructor) ft_autohinter_done,
(FT_Module_Requester) 0 (FT_Module_Requester) 0
}; };
/* END */

View File

@ -2,26 +2,31 @@
/* */ /* */
/* ahmodule.h */ /* ahmodule.h */
/* */ /* */
/* Auto-hinting module declaration */ /* Auto-hinting module (declaration). */
/* */ /* */
/* Copyright 2000: Catharon Productions Inc. */ /* Copyright 2000 Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#ifndef AHMODULE_H #ifndef AHMODULE_H
#define AHMODULE_H #define AHMODULE_H
#include <freetype/ftmodule.h> #include <freetype/ftmodule.h>
FT_EXPORT_VAR(const FT_Module_Class) autohint_module_class; FT_EXPORT_VAR( const FT_Module_Class ) autohint_module_class;
#endif /* AHMODULE_H */ #endif /* AHMODULE_H */
/* END */

View File

@ -1,106 +1,131 @@
/***************************************************************************/ /***************************************************************************/
/* */ /* */
/* FreeType Auto-Gridder Outline Optimisation */ /* ahoptim.c */
/* */ /* */
/* This module is in charge of optimising the outlines produced by the */ /* FreeType auto hinting outline optimization (body). */
/* auto-hinter in direct mode. This is required at small pixel sizes in */
/* order to ensure coherent spacing, among other things.. */
/* */ /* */
/* The technique used in this module is a simplified simulated annealing. */ /* Copyright 2000 Catharon Productions Inc. */
/* */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#include <freetype/internal/ftobjs.h> /* for ALLOC_ARRAY and FREE */
/*************************************************************************/
/* */
/* This module is in charge of optimising the outlines produced by the */
/* auto-hinter in direct mode. This is required at small pixel sizes in */
/* order to ensure coherent spacing, among other things.. */
/* */
/* The technique used in this module is a simplified simulated */
/* annealing. */
/* */
/*************************************************************************/
#include <freetype/internal/ftobjs.h> /* for ALLOC_ARRAY() and FREE() */
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
#include "ahoptim.h" #include "ahoptim.h"
#else #else
#include <autohint/ahoptim.h> #include <autohint/ahoptim.h>
#endif #endif
/* define this macro to use brute force optimisation, this is slow, but */
/* a good way to perfect the distortion function "by hand" through */
/* tweaking.. */
#define BRUTE_FORCE
#define xxxDEBUG_OPTIM /* define this macro to use brute force optimisation -- this is slow, */
/* but a good way to perfect the distortion function `by hand' through */
/* tweaking */
#define AH_BRUTE_FORCE
#define xxxAH_DEBUG_OPTIM
#undef LOG #undef LOG
#ifdef DEBUG_OPTIM #ifdef AH_DEBUG_OPTIM
#define LOG(x) optim_log##x
#else #define LOG( x ) optim_log##x
#define LOG(x)
#endif #else
#define LOG( x )
#endif /* AH_DEBUG_OPTIM */
#ifdef AH_DEBUG_OPTIM
#ifdef DEBUG_OPTIM
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define FLOAT(x) ((float)((x)/64.0)) #define FLOAT( x ) ( (float)( (x) / 64.0 ) )
static static
void optim_log( const char* fmt, ... ) void optim_log( const char* fmt, ... )
{ {
va_list ap; va_list ap;
va_start( ap, fmt ); va_start( ap, fmt );
vprintf( fmt, ap ); vprintf( fmt, ap );
va_end( ap ); va_end( ap );
} }
#endif
#ifdef DEBUG_OPTIM
static static
void AH_Dump_Stems( AH_Optimizer* optimizer ) void AH_Dump_Stems( AH_Optimizer* optimizer )
{ {
int n; int n;
AH_Stem* stem; AH_Stem* stem;
stem = optimizer->stems; stem = optimizer->stems;
for ( n = 0; n < optimizer->num_stems; n++, stem++ ) for ( n = 0; n < optimizer->num_stems; n++, stem++ )
{ {
LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}=<%1.f..%1.f> force=%.1f speed=%.1f\n", LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}="
"<%1.f..%1.f> force=%.1f speed=%.1f\n",
optimizer->vertical ? 'V' : 'H', n, optimizer->vertical ? 'V' : 'H', n,
FLOAT(stem->edge1->opos), FLOAT(stem->edge2->opos), FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ),
FLOAT(stem->edge1->pos), FLOAT(stem->edge2->pos), FLOAT( stem->edge1->pos ), FLOAT( stem->edge2->pos ),
FLOAT(stem->min_pos), FLOAT(stem->max_pos), FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
FLOAT(stem->force), FLOAT(stem->velocity) )); FLOAT( stem->force ), FLOAT( stem->velocity ) ));
} }
} }
static static
void AH_Dump_Stems2( AH_Optimizer* optimizer ) void AH_Dump_Stems2( AH_Optimizer* optimizer )
{ {
int n; int n;
AH_Stem* stem; AH_Stem* stem;
stem = optimizer->stems; stem = optimizer->stems;
for ( n = 0; n < optimizer->num_stems; n++, stem++ ) for ( n = 0; n < optimizer->num_stems; n++, stem++ )
{ {
LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n", LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n",
optimizer->vertical ? 'V' : 'H', n, optimizer->vertical ? 'V' : 'H', n,
FLOAT(stem->pos), FLOAT( stem->pos ),
FLOAT(stem->min_pos), FLOAT(stem->max_pos), FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
FLOAT(stem->force), FLOAT(stem->velocity) )); FLOAT( stem->force ), FLOAT( stem->velocity ) ));
} }
} }
static static
void AH_Dump_Springs( AH_Optimizer* optimizer ) void AH_Dump_Springs( AH_Optimizer* optimizer )
{ {
@ -108,20 +133,25 @@ void optim_log( const char* fmt, ... )
AH_Spring* spring; AH_Spring* spring;
AH_Stem* stems; AH_Stem* stems;
spring = optimizer->springs; spring = optimizer->springs;
stems = optimizer->stems; stems = optimizer->stems;
LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' )); LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' ));
for ( n = 0; n < optimizer->num_springs; n++, spring++ ) for ( n = 0; n < optimizer->num_springs; n++, spring++ )
{ {
LOG(( " [%d-%d:%.1f:%1.f:%.1f]", spring->stem1 - stems, spring->stem2 - stems, LOG(( " [%d-%d:%.1f:%1.f:%.1f]",
FLOAT(spring->owidth), spring->stem1 - stems, spring->stem2 - stems,
FLOAT(spring->stem2->pos-(spring->stem1->pos+spring->stem1->width)), FLOAT( spring->owidth ),
FLOAT(spring->tension) )); FLOAT( spring->stem2->pos -
( spring->stem1->pos + spring->stem1->width ) ),
FLOAT( spring->tension ) ));
} }
LOG(( "\n" )); LOG(( "\n" ));
} }
#endif
#endif /* AH_DEBUG_OPTIM */
/*************************************************************************/ /*************************************************************************/
@ -130,23 +160,27 @@ void optim_log( const char* fmt, ... )
/**** ****/ /**** ****/
/**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/ /**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/
/**** ****/ /**** ****/
/**** ****/
/**** ****/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
static static
int valid_stem_segments( AH_Segment* seg1, AH_Segment* seg2 ) int valid_stem_segments( AH_Segment* seg1,
AH_Segment* seg2 )
{ {
return seg1->serif == 0 && seg2 && seg2->link == seg1 && seg1->pos < seg2->pos && return seg1->serif == 0 &&
seg2 &&
seg2->link == seg1 &&
seg1->pos < seg2->pos &&
seg1->min_coord <= seg2->max_coord && seg1->min_coord <= seg2->max_coord &&
seg2->min_coord <= seg1->max_coord; seg2->min_coord <= seg1->max_coord;
} }
/* compute all stems in an outline */ /* compute all stems in an outline */
static static
int optim_compute_stems( AH_Optimizer* optimizer ) int optim_compute_stems( AH_Optimizer* optimizer )
{ {
AH_Outline* outline = optimizer->outline; AH_Outline* outline = optimizer->outline;
FT_Fixed scale; FT_Fixed scale;
@ -158,6 +192,7 @@ void optim_log( const char* fmt, ... )
AH_Stem** p_stems; AH_Stem** p_stems;
FT_Int* p_num_stems; FT_Int* p_num_stems;
edges = outline->horz_edges; edges = outline->horz_edges;
edge_limit = edges + outline->num_hedges; edge_limit = edges + outline->num_hedges;
scale = outline->y_scale; scale = outline->y_scale;
@ -171,25 +206,29 @@ void optim_log( const char* fmt, ... )
FT_Int num_stems = 0; FT_Int num_stems = 0;
AH_Edge* edge; AH_Edge* edge;
/* first of all, count the number of stems in this direction */ /* first of all, count the number of stems in this direction */
for ( edge = edges; edge < edge_limit; edge++ ) for ( edge = edges; edge < edge_limit; edge++ )
{ {
AH_Segment* seg = edge->first; AH_Segment* seg = edge->first;
do do
{ {
if (valid_stem_segments( seg, seg->link )) if (valid_stem_segments( seg, seg->link ) )
num_stems++; num_stems++;
seg = seg->edge_next; seg = seg->edge_next;
} while (seg != edge->first); } while ( seg != edge->first );
} }
/* now allocate the stems and build their table */ /* now allocate the stems and build their table */
if (num_stems > 0) if ( num_stems > 0 )
{ {
AH_Stem* stem; AH_Stem* stem;
if ( ALLOC_ARRAY( stems, num_stems, AH_Stem ) ) if ( ALLOC_ARRAY( stems, num_stems, AH_Stem ) )
goto Exit; goto Exit;
@ -198,14 +237,17 @@ void optim_log( const char* fmt, ... )
{ {
AH_Segment* seg = edge->first; AH_Segment* seg = edge->first;
AH_Segment* seg2; AH_Segment* seg2;
do do
{ {
seg2 = seg->link; seg2 = seg->link;
if (valid_stem_segments(seg,seg2)) if ( valid_stem_segments( seg, seg2 ) )
{ {
AH_Edge* edge1 = seg->edge; AH_Edge* edge1 = seg->edge;
AH_Edge* edge2 = seg2->edge; AH_Edge* edge2 = seg2->edge;
stem->edge1 = edge1; stem->edge1 = edge1;
stem->edge2 = edge2; stem->edge2 = edge2;
stem->opos = edge1->opos; stem->opos = edge1->opos;
@ -218,49 +260,51 @@ void optim_log( const char* fmt, ... )
FT_Pos min_coord = seg->min_coord; FT_Pos min_coord = seg->min_coord;
FT_Pos max_coord = seg->max_coord; FT_Pos max_coord = seg->max_coord;
if (seg2->min_coord > min_coord)
if ( seg2->min_coord > min_coord )
min_coord = seg2->min_coord; min_coord = seg2->min_coord;
if (seg2->max_coord < max_coord) if ( seg2->max_coord < max_coord )
max_coord = seg2->max_coord; max_coord = seg2->max_coord;
stem->min_coord = min_coord; stem->min_coord = min_coord;
stem->max_coord = max_coord; stem->max_coord = max_coord;
} }
/* compute minimum and maximum positions for stem */ /* compute minimum and maximum positions for stem -- */
/* note that the left-most/bottom-most stem has always */ /* note that the left-most/bottom-most stem has always */
/* a fixed position.. */ /* a fixed position */
if (stem == stems || edge1->blue_edge || edge2->blue_edge) if ( stem == stems || edge1->blue_edge || edge2->blue_edge )
{ {
/* this stem cannot move, it is snapped to a blue edge */ /* this stem cannot move; it is snapped to a blue edge */
stem->min_pos = stem->pos; stem->min_pos = stem->pos;
stem->max_pos = stem->pos; stem->max_pos = stem->pos;
} }
else else
{ {
/* this edge can move, compute its min and max positions */ /* this edge can move; compute its min and max positions */
FT_Pos pos1 = stem->opos; FT_Pos pos1 = stem->opos;
FT_Pos pos2 = pos1 + stem->owidth - stem->width; FT_Pos pos2 = pos1 + stem->owidth - stem->width;
FT_Pos min1 = (pos1 & -64); FT_Pos min1 = pos1 & -64;
FT_Pos min2 = (pos2 & -64); FT_Pos min2 = pos2 & -64;
stem->min_pos = min1; stem->min_pos = min1;
stem->max_pos = min1+64; stem->max_pos = min1 + 64;
if (min2 < min1) if ( min2 < min1 )
stem->min_pos = min2; stem->min_pos = min2;
else else
stem->max_pos = min2+64; stem->max_pos = min2 + 64;
/* XXX : just to see what it does */ /* XXX: just to see what it does */
stem->max_pos += 64; stem->max_pos += 64;
/* just for the case where direct hinting did some incredible */ /* just for the case where direct hinting did some */
/* things (e.g. blue edge shifts..) */ /* incredible things (e.g. blue edge shifts) */
if (stem->min_pos > stem->pos) if ( stem->min_pos > stem->pos )
stem->min_pos = stem->pos; stem->min_pos = stem->pos;
if (stem->max_pos < stem->pos) if ( stem->max_pos < stem->pos )
stem->max_pos = stem->pos; stem->max_pos = stem->pos;
} }
@ -270,8 +314,8 @@ void optim_log( const char* fmt, ... )
stem++; stem++;
} }
seg = seg->edge_next; seg = seg->edge_next;
}
while (seg != edge->first); } while ( seg != edge->first );
} }
} }
@ -285,17 +329,21 @@ void optim_log( const char* fmt, ... )
p_stems = &optimizer->vert_stems; p_stems = &optimizer->vert_stems;
p_num_stems = &optimizer->num_vstems; p_num_stems = &optimizer->num_vstems;
} }
Exit: Exit:
#ifdef DEBUG_OPTIM
AH_Dump_Stems(optimizer); #ifdef AH_DEBUG_OPTIM
#endif AH_Dump_Stems( optimizer );
#endif
return error; return error;
} }
/* returns the spring area between two stems, 0 if none */ /* returns the spring area between two stems, 0 if none */
static static
FT_Pos stem_spring_area( AH_Stem* stem1, AH_Stem* stem2 ) FT_Pos stem_spring_area( AH_Stem* stem1,
AH_Stem* stem2 )
{ {
FT_Pos area1 = stem1->max_coord - stem1->min_coord; FT_Pos area1 = stem1->max_coord - stem1->min_coord;
FT_Pos area2 = stem2->max_coord - stem2->min_coord; FT_Pos area2 = stem2->max_coord - stem2->min_coord;
@ -303,18 +351,19 @@ void optim_log( const char* fmt, ... )
FT_Pos max = stem1->max_coord; FT_Pos max = stem1->max_coord;
FT_Pos area; FT_Pos area;
/* order stems */ /* order stems */
if (stem2->opos <= stem1->opos + stem1->owidth) if ( stem2->opos <= stem1->opos + stem1->owidth )
return 0; return 0;
if (min < stem2->min_coord) if ( min < stem2->min_coord )
min = stem2->min_coord; min = stem2->min_coord;
if (max < stem2->max_coord) if ( max < stem2->max_coord )
max = stem2->max_coord; max = stem2->max_coord;
area = (max-min); area = ( max-min );
if ( 2*area < area1 && 2*area < area2 ) if ( 2 * area < area1 && 2 * area < area2 )
area = 0; area = 0;
return area; return area;
@ -326,7 +375,7 @@ void optim_log( const char* fmt, ... )
int optim_compute_springs( AH_Optimizer* optimizer ) int optim_compute_springs( AH_Optimizer* optimizer )
{ {
/* basically, a spring exists between two stems if most of their */ /* basically, a spring exists between two stems if most of their */
/* surface is aligned.. */ /* surface is aligned */
FT_Memory memory = optimizer->memory; FT_Memory memory = optimizer->memory;
AH_Stem* stems; AH_Stem* stems;
@ -338,6 +387,7 @@ void optim_log( const char* fmt, ... )
FT_Int* p_num_springs; FT_Int* p_num_springs;
AH_Spring** p_springs; AH_Spring** p_springs;
stems = optimizer->horz_stems; stems = optimizer->horz_stems;
stem_limit = stems + optimizer->num_hstems; stem_limit = stems + optimizer->num_hstems;
@ -349,20 +399,24 @@ void optim_log( const char* fmt, ... )
FT_Int num_springs = 0; FT_Int num_springs = 0;
AH_Spring* springs = 0; AH_Spring* springs = 0;
/* first of all, count stem springs */ /* first of all, count stem springs */
for ( stem = stems; stem+1 < stem_limit; stem++ ) for ( stem = stems; stem + 1 < stem_limit; stem++ )
{ {
AH_Stem* stem2; AH_Stem* stem2;
for ( stem2 = stem+1; stem2 < stem_limit; stem2++ ) for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
if (stem_spring_area(stem,stem2)) if ( stem_spring_area( stem, stem2 ) )
num_springs++; num_springs++;
} }
/* then allocate and build the springs table */ /* then allocate and build the springs table */
if (num_springs > 0) if ( num_springs > 0 )
{ {
AH_Spring* spring; AH_Spring* spring;
/* allocate table of springs */ /* allocate table of springs */
if ( ALLOC_ARRAY( springs, num_springs, AH_Spring ) ) if ( ALLOC_ARRAY( springs, num_springs, AH_Spring ) )
goto Exit; goto Exit;
@ -374,15 +428,16 @@ void optim_log( const char* fmt, ... )
AH_Stem* stem2; AH_Stem* stem2;
FT_Pos area; FT_Pos area;
for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ )
{ {
area = stem_spring_area(stem,stem2); area = stem_spring_area( stem, stem2 );
if (area) if ( area )
{ {
/* add a new spring here */ /* add a new spring here */
spring->stem1 = stem; spring->stem1 = stem;
spring->stem2 = stem2; spring->stem2 = stem2;
spring->owidth = stem2->opos - (stem->opos + stem->owidth); spring->owidth = stem2->opos - ( stem->opos + stem->owidth );
spring->tension = 0; spring->tension = 0;
spring++; spring++;
@ -401,31 +456,35 @@ void optim_log( const char* fmt, ... )
} }
Exit: Exit:
#ifdef DEBUG_OPTIM
AH_Dump_Springs(optimizer); #ifdef AH_DEBUG_OPTIM
#endif AH_Dump_Springs( optimizer );
#endif
return error; return error;
} }
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/**** ****/ /**** ****/
/**** OPTIMISE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/ /**** OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/
/**** ****/
/**** ****/
/**** ****/ /**** ****/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
#ifndef BRUTE_FORCE #ifndef AH_BRUTE_FORCE
/* compute all spring tensions */ /* compute all spring tensions */
static static
void optim_compute_tensions( AH_Optimizer* optimizer ) void optim_compute_tensions( AH_Optimizer* optimizer )
{ {
AH_Spring* spring = optimizer->springs; AH_Spring* spring = optimizer->springs;
AH_Spring* limit = spring + optimizer->num_springs; AH_Spring* limit = spring + optimizer->num_springs;
for ( ; spring < limit; spring++ ) for ( ; spring < limit; spring++ )
{ {
AH_Stem* stem1 = spring->stem1; AH_Stem* stem1 = spring->stem1;
@ -436,111 +495,115 @@ void optim_log( const char* fmt, ... )
FT_Pos tension; FT_Pos tension;
FT_Pos sign; FT_Pos sign;
/* compute the tension, it simply is -K*(new_width-old_width) */
width = stem2->pos - (stem1->pos + stem1->width); /* compute the tension; it simply is -K*(new_width-old_width) */
tension = width - spring->owidth; width = stem2->pos - ( stem1->pos + stem1->width );
tension = width - spring->owidth;
sign = 1; sign = 1;
if (tension < 0) if ( tension < 0 )
{ {
sign = -1; sign = -1;
tension = -tension; tension = -tension;
} }
if (width <= 0) if ( width <= 0 )
tension = 32000; tension = 32000;
else else
tension = (tension << 10)/width; tension = ( tension << 10 ) / width;
tension = -sign*FT_MulFix( tension, optimizer->tension_scale ); tension = -sign * FT_MulFix( tension, optimizer->tension_scale );
spring->tension = tension; spring->tension = tension;
/* now, distribute tension among the englobing stems, if they */ /* now, distribute tension among the englobing stems, if they */
/* are able to move.. */ /* are able to move */
status = 0; status = 0;
if (stem1->pos <= stem1->min_pos) if ( stem1->pos <= stem1->min_pos )
status |= 1; status |= 1;
if (stem2->pos >= stem2->max_pos) if ( stem2->pos >= stem2->max_pos )
status |= 2; status |= 2;
if (!status) if ( !status )
tension /= 2; tension /= 2;
if ((status & 1)== 0) if ( ( status & 1 ) == 0 )
stem1->force -= tension; stem1->force -= tension;
if ((status & 2)== 0) if ( ( status & 2 ) == 0 )
stem2->force += tension; stem2->force += tension;
} }
} }
/* compute all stem movements -- returns 0 if nothing moved */
/* compute all stem movements - returns 0 if nothing moved */
static static
int optim_compute_stem_movements( AH_Optimizer* optimizer ) int optim_compute_stem_movements( AH_Optimizer* optimizer )
{ {
AH_Stem* stems = optimizer->stems; AH_Stem* stems = optimizer->stems;
AH_Stem* limit = stems + optimizer->num_stems; AH_Stem* limit = stems + optimizer->num_stems;
AH_Stem* stem = stems; AH_Stem* stem = stems;
int moved = 0; int moved = 0;
/* set initial forces to velocity */ /* set initial forces to velocity */
for ( stem = stems; stem < limit; stem++ ) for ( stem = stems; stem < limit; stem++ )
{ {
stem->force = stem->velocity; stem->force = stem->velocity;
stem->velocity /= 2; /* XXXX: Heuristics */ stem->velocity /= 2; /* XXX: Heuristics */
} }
/* compute the sum of forces applied on each stem */ /* compute the sum of forces applied on each stem */
optim_compute_tensions( optimizer ); optim_compute_tensions( optimizer );
#ifdef DEBUG_OPTIM
#ifdef AH_DEBUG_OPTIM
AH_Dump_Springs( optimizer ); AH_Dump_Springs( optimizer );
AH_Dump_Stems2( optimizer ); AH_Dump_Stems2( optimizer );
#endif #endif
/* now, see if something can move ? */ /* now, see whether something can move */
for ( stem = stems; stem < limit; stem++ ) for ( stem = stems; stem < limit; stem++ )
{ {
if (stem->force > optimizer->tension_threshold) if ( stem->force > optimizer->tension_threshold )
{ {
/* there is enough tension to move the stem to the right */ /* there is enough tension to move the stem to the right */
if (stem->pos < stem->max_pos) if ( stem->pos < stem->max_pos )
{ {
stem->pos += 64; stem->pos += 64;
stem->velocity = stem->force/2; stem->velocity = stem->force / 2;
moved = 1; moved = 1;
} }
else else
stem->velocity = 0; stem->velocity = 0;
} }
else if (stem->force < optimizer->tension_threshold) else if ( stem->force < optimizer->tension_threshold )
{ {
/* there is enough tension to move the stem to the left */ /* there is enough tension to move the stem to the left */
if (stem->pos > stem->min_pos) if ( stem->pos > stem->min_pos )
{ {
stem->pos -= 64; stem->pos -= 64;
stem->velocity = stem->force/2; stem->velocity = stem->force / 2;
moved = 1; moved = 1;
} }
else else
stem->velocity = 0; stem->velocity = 0;
} }
} }
/* return 0 if nothing moved */ /* return 0 if nothing moved */
return moved; return moved;
} }
#endif /* BRUTE_FORCE */ #endif /* AH_BRUTE_FORCE */
/* compute current global distortion from springs */ /* compute current global distortion from springs */
static static
FT_Pos optim_compute_distorsion( AH_Optimizer* optimizer ) FT_Pos optim_compute_distortion( AH_Optimizer* optimizer )
{ {
AH_Spring* spring = optimizer->springs; AH_Spring* spring = optimizer->springs;
AH_Spring* limit = spring + optimizer->num_springs; AH_Spring* limit = spring + optimizer->num_springs;
FT_Pos distorsion = 0; FT_Pos distortion = 0;
for ( ; spring < limit; spring++ ) for ( ; spring < limit; spring++ )
{ {
@ -548,32 +611,34 @@ void optim_log( const char* fmt, ... )
AH_Stem* stem2 = spring->stem2; AH_Stem* stem2 = spring->stem2;
FT_Pos width; FT_Pos width;
width = stem2->pos - (stem1->pos + stem1->width); width = stem2->pos - ( stem1->pos + stem1->width );
width -= spring->owidth; width -= spring->owidth;
if (width < 0) if ( width < 0 )
width = -width; width = -width;
distorsion += width; distortion += width;
} }
return distorsion;
return distortion;
} }
/* record stems configuration in "best of" history */ /* record stems configuration in `best of' history */
static static
void optim_record_configuration( AH_Optimizer* optimizer ) void optim_record_configuration( AH_Optimizer* optimizer )
{ {
FT_Pos distorsion; FT_Pos distortion;
AH_Configuration* configs = optimizer->configs; AH_Configuration* configs = optimizer->configs;
AH_Configuration* limit = configs + optimizer->num_configs; AH_Configuration* limit = configs + optimizer->num_configs;
AH_Configuration* config; AH_Configuration* config;
distorsion = optim_compute_distorsion( optimizer );
LOG(( "config distorsion = %.1f ", FLOAT(distorsion*64) )); distortion = optim_compute_distortion( optimizer );
LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) ));
/* check that we really need to add this configuration to our */ /* check that we really need to add this configuration to our */
/* sorted history.. */ /* sorted history */
if ( limit > configs && limit[-1].distorsion < distorsion ) if ( limit > configs && limit[-1].distortion < distortion )
{ {
LOG(( "ejected\n" )); LOG(( "ejected\n" ));
return; return;
@ -583,46 +648,50 @@ void optim_log( const char* fmt, ... )
{ {
int n; int n;
config = limit; config = limit;
if (optimizer->num_configs < AH_MAX_CONFIGS) if ( optimizer->num_configs < AH_MAX_CONFIGS )
optimizer->num_configs++; optimizer->num_configs++;
else else
config--; config--;
config->distorsion = distorsion; config->distortion = distortion;
for ( n = 0; n < optimizer->num_stems; n++ ) for ( n = 0; n < optimizer->num_stems; n++ )
config->positions[n] = optimizer->stems[n].pos; config->positions[n] = optimizer->stems[n].pos;
} }
/* move the current configuration towards the front of the list */ /* move the current configuration towards the front of the list */
/* when necessary, yes this is slow bubble sort ;-) */ /* when necessary -- yes this is slow bubble sort ;-) */
while ( config > configs && config[0].distorsion < config[-1].distorsion ) while ( config > configs && config[0].distortion < config[-1].distortion )
{ {
AH_Configuration temp; AH_Configuration temp;
config--; config--;
temp = config[0]; temp = config[0];
config[0] = config[1]; config[0] = config[1];
config[1] = temp; config[1] = temp;
} }
LOG(( "recorded !!\n" )); LOG(( "recorded!\n" ));
} }
#ifdef BRUTE_FORCE #ifdef AH_BRUTE_FORCE
/* optimize outline in a single direction */ /* optimize outline in a single direction */
static static
void optim_compute( AH_Optimizer* optimizer ) void optim_compute( AH_Optimizer* optimizer )
{ {
int n; int n;
FT_Bool moved; FT_Bool moved;
AH_Stem* stem = optimizer->stems; AH_Stem* stem = optimizer->stems;
AH_Stem* limit = stem + optimizer->num_stems; AH_Stem* limit = stem + optimizer->num_stems;
/* empty, exit */ /* empty, exit */
if (stem >= limit) if ( stem >= limit )
return; return;
optimizer->num_configs = 0; optimizer->num_configs = 0;
@ -634,13 +703,13 @@ void optim_log( const char* fmt, ... )
do do
{ {
/* record current configuration */ /* record current configuration */
optim_record_configuration(optimizer); optim_record_configuration( optimizer );
/* now change configuration */ /* now change configuration */
moved = 0; moved = 0;
for ( stem = optimizer->stems; stem < limit; stem++ ) for ( stem = optimizer->stems; stem < limit; stem++ )
{ {
if (stem->pos < stem->max_pos) if ( stem->pos < stem->max_pos )
{ {
stem->pos += 64; stem->pos += 64;
moved = 1; moved = 1;
@ -649,8 +718,7 @@ void optim_log( const char* fmt, ... )
stem->pos = stem->min_pos; stem->pos = stem->min_pos;
} }
} } while ( moved );
while (moved);
/* now, set the best stem positions */ /* now, set the best stem positions */
for ( n = 0; n < optimizer->num_stems; n++ ) for ( n = 0; n < optimizer->num_stems; n++ )
@ -658,6 +726,7 @@ void optim_log( const char* fmt, ... )
AH_Stem* stem = optimizer->stems + n; AH_Stem* stem = optimizer->stems + n;
FT_Pos pos = optimizer->configs[0].positions[n]; FT_Pos pos = optimizer->configs[0].positions[n];
stem->edge1->pos = pos; stem->edge1->pos = pos;
stem->edge2->pos = pos + stem->width; stem->edge2->pos = pos + stem->width;
@ -665,31 +734,36 @@ void optim_log( const char* fmt, ... )
stem->edge2->flags |= ah_edge_done; stem->edge2->flags |= ah_edge_done;
} }
} }
#else
#else /* AH_BRUTE_FORCE */
/* optimize outline in a single direction */ /* optimize outline in a single direction */
static static
void optim_compute( AH_Optimizer* optimizer ) void optim_compute( AH_Optimizer* optimizer )
{ {
int n, counter, counter2; int n, counter, counter2;
optimizer->num_configs = 0; optimizer->num_configs = 0;
optimizer->tension_scale = 0x80000L; optimizer->tension_scale = 0x80000L;
optimizer->tension_threshold = 64; optimizer->tension_threshold = 64;
/* record initial configuration threshold */ /* record initial configuration threshold */
optim_record_configuration(optimizer); optim_record_configuration( optimizer );
counter = 0; counter = 0;
for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- ) for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- )
{ {
if (counter == 0) if ( counter == 0 )
counter = 2*optimizer->num_stems; counter = 2 * optimizer->num_stems;
if (!optim_compute_stem_movements( optimizer )) if ( !optim_compute_stem_movements( optimizer ) )
break; break;
optim_record_configuration(optimizer); optim_record_configuration( optimizer );
counter--; counter--;
if (counter == 0) if ( counter == 0 )
optimizer->tension_scale /= 2; optimizer->tension_scale /= 2;
} }
@ -699,6 +773,7 @@ void optim_log( const char* fmt, ... )
AH_Stem* stem = optimizer->stems + n; AH_Stem* stem = optimizer->stems + n;
FT_Pos pos = optimizer->configs[0].positions[n]; FT_Pos pos = optimizer->configs[0].positions[n];
stem->edge1->pos = pos; stem->edge1->pos = pos;
stem->edge2->pos = pos + stem->width; stem->edge2->pos = pos + stem->width;
@ -706,7 +781,9 @@ void optim_log( const char* fmt, ... )
stem->edge2->flags |= ah_edge_done; stem->edge2->flags |= ah_edge_done;
} }
} }
#endif
#endif /* AH_BRUTE_FORCE */
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
@ -714,19 +791,19 @@ void optim_log( const char* fmt, ... )
/**** ****/ /**** ****/
/**** HIGH-LEVEL OPTIMIZER API ****/ /**** HIGH-LEVEL OPTIMIZER API ****/
/**** ****/ /**** ****/
/**** ****/
/**** ****/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/* releases the optimisation data */ /* releases the optimization data */
void AH_Optimizer_Done( AH_Optimizer* optimizer ) void AH_Optimizer_Done( AH_Optimizer* optimizer )
{ {
if (optimizer) if ( optimizer )
{ {
FT_Memory memory = optimizer->memory; FT_Memory memory = optimizer->memory;
FREE( optimizer->horz_stems ); FREE( optimizer->horz_stems );
FREE( optimizer->vert_stems ); FREE( optimizer->vert_stems );
FREE( optimizer->horz_springs ); FREE( optimizer->horz_springs );
@ -735,6 +812,7 @@ void optim_log( const char* fmt, ... )
} }
} }
/* loads the outline into the optimizer */ /* loads the outline into the optimizer */
int AH_Optimizer_Init( AH_Optimizer* optimizer, int AH_Optimizer_Init( AH_Optimizer* optimizer,
AH_Outline* outline, AH_Outline* outline,
@ -742,7 +820,8 @@ void optim_log( const char* fmt, ... )
{ {
FT_Error error; FT_Error error;
MEM_Set( optimizer, 0, sizeof(*optimizer));
MEM_Set( optimizer, 0, sizeof ( *optimizer ) );
optimizer->outline = outline; optimizer->outline = outline;
optimizer->memory = memory; optimizer->memory = memory;
@ -750,22 +829,26 @@ void optim_log( const char* fmt, ... )
/* compute stems and springs */ /* compute stems and springs */
error = optim_compute_stems ( optimizer ) || error = optim_compute_stems ( optimizer ) ||
optim_compute_springs( optimizer ); optim_compute_springs( optimizer );
if (error) goto Fail; if ( error )
goto Fail;
/* allocate stem positions history and configurations */ /* allocate stem positions history and configurations */
{ {
int n, max_stems; int n, max_stems;
max_stems = optimizer->num_hstems; max_stems = optimizer->num_hstems;
if (max_stems < optimizer->num_vstems) if ( max_stems < optimizer->num_vstems )
max_stems = optimizer->num_vstems; max_stems = optimizer->num_vstems;
if ( ALLOC_ARRAY( optimizer->positions, max_stems*AH_MAX_CONFIGS, FT_Pos ) ) if ( ALLOC_ARRAY( optimizer->positions,
max_stems * AH_MAX_CONFIGS, FT_Pos ) )
goto Fail; goto Fail;
optimizer->num_configs = 0; optimizer->num_configs = 0;
for ( n = 0; n < AH_MAX_CONFIGS; n++ ) for ( n = 0; n < AH_MAX_CONFIGS; n++ )
optimizer->configs[n].positions = optimizer->positions + n*max_stems; optimizer->configs[n].positions = optimizer->positions +
n * max_stems;
} }
return error; return error;
@ -784,9 +867,9 @@ void optim_log( const char* fmt, ... )
optimizer->num_springs = optimizer->num_hsprings; optimizer->num_springs = optimizer->num_hsprings;
optimizer->springs = optimizer->horz_springs; optimizer->springs = optimizer->horz_springs;
if (optimizer->num_springs > 0) if ( optimizer->num_springs > 0 )
{ {
LOG(( "horizontal optimisation ------------------------\n" )); LOG(( "horizontal optimization ------------------------\n" ));
optim_compute( optimizer ); optim_compute( optimizer );
} }
@ -795,14 +878,12 @@ void optim_log( const char* fmt, ... )
optimizer->num_springs = optimizer->num_vsprings; optimizer->num_springs = optimizer->num_vsprings;
optimizer->springs = optimizer->vert_springs; optimizer->springs = optimizer->vert_springs;
if (optimizer->num_springs) if ( optimizer->num_springs )
{ {
LOG(( "vertical optimisation --------------------------\n" )); LOG(( "vertical optimization --------------------------\n" ));
optim_compute( optimizer ); optim_compute( optimizer );
} }
} }
/* END */

View File

@ -1,64 +1,68 @@
/***************************************************************************/ /***************************************************************************/
/* */ /* */
/* FreeType Auto-Gridder Outline Optimisation */ /* ahoptim.h */
/* */ /* */
/* This module is in charge of optimising the outlines produced by the */ /* FreeType auto hinting outline optimization (declaration). */
/* auto-hinter in direct mode. This is required at small pixel sizes in */
/* order to ensure coherent spacing, among other things.. */
/* */ /* */
/* The technique used in this module is a simplified simulated annealing. */ /* Copyright 2000 Catharon Productions Inc. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#ifndef AGOPTIM_H
#define AGOPTIM_H #ifndef AHOPTIM_H
#define AHOPTIM_H
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
#include "ahtypes.h" #include "ahtypes.h"
#else #else
#include <autohint/ahtypes.h> #include <autohint/ahtypes.h>
#endif #endif
/* the maximal number of stem configurations to record during optimisation */
/* the maximal number of stem configurations to record */
/* during optimization */
#define AH_MAX_CONFIGS 8 #define AH_MAX_CONFIGS 8
typedef struct AH_Stem_ typedef struct AH_Stem_
{ {
FT_Pos pos; /* current position */ FT_Pos pos; /* current position */
FT_Pos velocity; /* current velocity */ FT_Pos velocity; /* current velocity */
FT_Pos force; /* sum of current forces */ FT_Pos force; /* sum of current forces */
FT_Pos width; /* normalized width */ FT_Pos width; /* normalized width */
FT_Pos min_pos; /* minimum grid position */ FT_Pos min_pos; /* minimum grid position */
FT_Pos max_pos; /* maximum grid position */ FT_Pos max_pos; /* maximum grid position */
AH_Edge* edge1; /* left/bottom edge */ AH_Edge* edge1; /* left/bottom edge */
AH_Edge* edge2; /* right/top edge */ AH_Edge* edge2; /* right/top edge */
FT_Pos opos; /* original position */ FT_Pos opos; /* original position */
FT_Pos owidth; /* original width */ FT_Pos owidth; /* original width */
FT_Pos min_coord; /* minimum coordinate */ FT_Pos min_coord; /* minimum coordinate */
FT_Pos max_coord; /* maximum coordinate */ FT_Pos max_coord; /* maximum coordinate */
} AH_Stem; } AH_Stem;
/* A spring between two stems */ /* A spring between two stems */
typedef struct AH_Spring_ typedef struct AH_Spring_
{ {
AH_Stem* stem1; AH_Stem* stem1;
AH_Stem* stem2; AH_Stem* stem2;
@ -69,69 +73,64 @@
/* A configuration records the position of each stem at a given time */ /* A configuration records the position of each stem at a given time */
/* as well as the associated distortion.. */ /* as well as the associated distortion */
typedef struct AH_Configuration_ typedef struct AH_Configuration_
{ {
FT_Pos* positions; FT_Pos* positions;
FT_Long distorsion; FT_Long distortion;
} AH_Configuration; } AH_Configuration;
typedef struct AH_Optimizer_
typedef struct AH_Optimizer_
{ {
FT_Memory memory; FT_Memory memory;
AH_Outline* outline; AH_Outline* outline;
FT_Int num_hstems; FT_Int num_hstems;
AH_Stem* horz_stems; AH_Stem* horz_stems;
FT_Int num_vstems; FT_Int num_vstems;
AH_Stem* vert_stems; AH_Stem* vert_stems;
FT_Int num_hsprings; FT_Int num_hsprings;
FT_Int num_vsprings; FT_Int num_vsprings;
AH_Spring* horz_springs; AH_Spring* horz_springs;
AH_Spring* vert_springs; AH_Spring* vert_springs;
FT_Int num_configs; FT_Int num_configs;
AH_Configuration configs[ AH_MAX_CONFIGS ]; AH_Configuration configs[AH_MAX_CONFIGS];
FT_Pos* positions; FT_Pos* positions;
/* during each pass, use these instead */ /* during each pass, use these instead */
FT_Int num_stems; FT_Int num_stems;
AH_Stem* stems; AH_Stem* stems;
FT_Int num_springs; FT_Int num_springs;
AH_Spring* springs; AH_Spring* springs;
FT_Bool vertical; FT_Bool vertical;
FT_Fixed tension_scale; FT_Fixed tension_scale;
FT_Pos tension_threshold; FT_Pos tension_threshold;
} AH_Optimizer; } AH_Optimizer;
/* loads the outline into the optimizer */ /* loads the outline into the optimizer */
extern
int AH_Optimizer_Init( AH_Optimizer* optimizer, int AH_Optimizer_Init( AH_Optimizer* optimizer,
AH_Outline* outline, AH_Outline* outline,
FT_Memory memory ); FT_Memory memory );
/* compute optimal outline */ /* compute optimal outline */
extern
void AH_Optimizer_Compute( AH_Optimizer* optimizer ); void AH_Optimizer_Compute( AH_Optimizer* optimizer );
/* release the optimization data */
/* releases the optimisation data */
extern
void AH_Optimizer_Done( AH_Optimizer* optimizer ); void AH_Optimizer_Done( AH_Optimizer* optimizer );
#endif /* AGOPTIM_H */ #endif /* AHOPTIM_H */
/* END */

View File

@ -2,181 +2,216 @@
/* */ /* */
/* ahtypes.h */ /* ahtypes.h */
/* */ /* */
/* General types and definitions for the auto-hint module */ /* General types and definitions for the auto-hint module */
/* (specification only). */
/* */ /* */
/* Copyright 2000: Catharon Productions Inc. */ /* Copyright 2000 Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#ifndef AGTYPES_H
#define AGTYPES_H
#include <freetype/internal/ftobjs.h> /* for freetype.h + LOCAL_DEF etc.. */ #ifndef AHTYPES_H
#define AHTYPES_H
#include <freetype/internal/ftobjs.h> /* for freetype.h + LOCAL_DEF etc. */
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
#include "ahloader.h" /* glyph loader types & declarations */
#include "ahloader.h"
#else #else
#include <autohint/ahloader.h> /* glyph loader types & declarations */
#include <autohint/ahloader.h>
#endif #endif
#define xxDEBUG_AG
#ifdef DEBUG_AG #define xxAH_DEBUG
#ifdef AH_DEBUG
#include <stdio.h> #include <stdio.h>
#define AH_LOG(x) printf##x
#define AH_LOG( x ) printf##x
#else #else
#define AH_LOG(x) /* nothing */
#define AH_LOG( x ) do ; while ( 0 ) /* nothing */
#endif #endif
/***************************************************************************/ /*************************************************************************/
/***************************************************************************/ /*************************************************************************/
/***************************************************************************/ /*************************************************************************/
/**** ****/ /**** ****/
/**** COMPILE-TIME BUILD OPTIONS ****/ /**** COMPILE-TIME BUILD OPTIONS ****/
/**** ****/ /**** ****/
/**** Toggle these configuration macros to experiment with ****/ /**** Toggle these configuration macros to experiment with `features' ****/
/**** "features" of the auto-hinter.. ****/ /**** of the auto-hinter. ****/
/**** ****/ /**** ****/
/***************************************************************************/ /*************************************************************************/
/***************************************************************************/ /*************************************************************************/
/***************************************************************************/ /*************************************************************************/
/* if this option is defined, only strong interpolation will be used to */
/* place the points between edges. Otherwise, "smooth" points are detected */
/* and later hinted through weak interpolation to correct some unpleasant */
/* artefacts.. */
/* */
#undef AH_OPTION_NO_WEAK_INTERPOLATION
#undef AH_OPTION_NO_STRONG_INTERPOLATION
/* undefine this macro if you don't want to hint the metrics */ /*************************************************************************/
/* there is no reason to do this, except for experimentation */ /* */
/* If this option is defined, only strong interpolation will be used to */
/* place the points between edges. Otherwise, `smooth' points are */
/* detected and later hinted through weak interpolation to correct some */
/* unpleasant artefacts. */
/* */
#undef AH_OPTION_NO_WEAK_INTERPOLATION
/*************************************************************************/
/* */
/* If this option is defined, only weak interpolation will be used to */
/* place the points between edges. Otherwise, `strong' points are */
/* detected and later hinted through strong interpolation to correct */
/* some unpleasant artefacts. */
/* */
#undef AH_OPTION_NO_STRONG_INTERPOLATION
/*************************************************************************/
/* */
/* Undefine this macro if you don't want to hint the metrics. There is */
/* no reason to do this (at least for non-CJK scripts), except for */
/* experimentation. */
/* */
#define AH_HINT_METRICS #define AH_HINT_METRICS
/* define this macro if you do not want to insert extra edges at a glyph's */
/* x and y extrema (when there isn't one already available). This help */
/* reduce a number of artefacts and allow hinting of metrics.. */
/* */
#undef AH_OPTION_NO_EXTREMUM_EDGES
/* don't touch for now.. */ /*************************************************************************/
/* */
/* Define this macro if you do not want to insert extra edges at a */
/* glyph's x and y extremum (if there isn't one already available). */
/* This helps to reduce a number of artefacts and allows hinting of */
/* metrics. */
/* */
#undef AH_OPTION_NO_EXTREMUM_EDGES
/* don't touch for now */
#define AH_MAX_WIDTHS 12 #define AH_MAX_WIDTHS 12
#define AH_MAX_HEIGHTS 12 #define AH_MAX_HEIGHTS 12
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/**** ****/
/**** TYPES DEFINITIONS ****/
/**** ****/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/* see agangles.h */ /*************************************************************************/
typedef FT_Int AH_Angle; /*************************************************************************/
/*************************************************************************/
/**** ****/
/**** TYPE DEFINITIONS ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* hint flags */ /* see agangles.h */
typedef enum AH_Flags_ typedef FT_Int AH_Angle;
{
ah_flah_none = 0,
/* bezier control points flags */
ah_flah_conic = 1,
ah_flah_cubic = 2,
ah_flah_control = ah_flah_conic | ah_flah_cubic,
/* extrema flags */
ah_flah_extrema_x = 4,
ah_flah_extrema_y = 8,
/* roundness */
ah_flah_round_x = 16,
ah_flah_round_y = 32,
/* touched */
ah_flah_touch_x = 64,
ah_flah_touch_y = 128,
/* weak interpolation */
ah_flah_weak_interpolation = 256,
/* never remove this one !! */
ah_flah_max
} AH_Flags;
/* edge hint flags */ /* hint flags */
typedef enum AH_Edge_Flags_ #define ah_flah_none 0
{
ah_edge_normal = 0,
ah_edge_round = 1,
ah_edge_serif = 2,
ah_edge_done = 4
} AH_Edge_Flags; /* bezier control points flags */
#define ah_flah_conic 1
#define ah_flah_cubic 2
#define ah_flah_control ( ah_flah_conic | ah_flah_cubic )
/* extrema flags */
#define ah_flah_extrema_x 4
#define ah_flah_extrema_y 8
/* roundness */
#define ah_flah_round_x 16
#define ah_flah_round_y 32
/* touched */
#define ah_flah_touch_x 64
#define ah_flah_touch_y 128
/* weak interpolation */
#define ah_flah_weak_interpolation 256
typedef FT_Int AH_Flags;
/* hint directions - the values are computed so that two vectors are */ /* edge hint flags */
/* in opposite directions iff "dir1+dir2 == 0" */ #define ah_edge_normal 0
typedef enum AH_Direction_ #define ah_edge_round 1
{ #define ah_edge_serif 2
ah_dir_none = 4, #define ah_edge_done 4
ah_dir_right = 1,
ah_dir_left = -1,
ah_dir_up_and_down = 0,
ah_dir_left_and_right = 0,
ah_dir_up = 2,
ah_dir_down = -2
} AH_Direction; typedef FT_Int AH_Edge_Flags;
/* hint directions -- the values are computed so that two vectors are */
/* in opposite directions iff `dir1+dir2 == 0' */
#define ah_dir_none 4
#define ah_dir_right 1
#define ah_dir_left -1
#define ah_dir_up 2
#define ah_dir_down -2
typedef FT_Int AH_Direction;
typedef struct AH_Point AH_Point; typedef struct AH_Point AH_Point;
typedef struct AH_Segment AH_Segment; typedef struct AH_Segment AH_Segment;
typedef struct AH_Edge AH_Edge; typedef struct AH_Edge AH_Edge;
/***************************************************************************
* /*************************************************************************/
* <Struct> /* */
* AH_Point /* <Struct> */
* /* AH_Point */
* <Description> /* */
* A structure used to model an outline point to the AH_Outline type /* <Description> */
* /* A structure used to model an outline point to the AH_Outline type. */
* <Fields> /* */
* flags :: current point hint flags /* <Fields> */
* ox, oy :: current original scaled coordinates /* flags :: The current point hint flags. */
* fx, fy :: current coordinates in font units /* */
* x, y :: current hinter coordinates /* ox, oy :: The current original scaled coordinates. */
* u, v :: point coordinates - meaning varies with context /* */
* /* fx, fy :: The current coordinates in font units. */
* in_dir :: direction of inwards vector (prev->point) /* */
* out_dir :: direction of outwards vector (point->next) /* x, y :: The current hinter coordinates. */
* /* */
* in_angle :: angle of inwards vector /* u, v :: Point coordinates -- meaning varies with context. */
* out_angle :: angle of outwards vector /* */
* /* in_dir :: The direction of the inwards vector (prev->point). */
* next :: next point in same contour /* */
* prev :: previous point in same contour /* out_dir :: The direction of the outwards vector (point->next). */
* /* */
*/ /* in_angle :: The angle of the inwards vector. */
/* */
/* out_angle :: The angle of the outwards vector. */
/* */
/* next :: The next point in same contour. */
/* */
/* prev :: The previous point in same contour. */
/* */
struct AH_Point struct AH_Point
{ {
AH_Flags flags; /* point flags used by hinter */ AH_Flags flags; /* point flags used by hinter */
FT_Pos ox, oy; FT_Pos ox, oy;
FT_Pos fx, fy; FT_Pos fx, fy;
FT_Pos x, y; FT_Pos x, y;
@ -188,226 +223,239 @@
AH_Angle in_angle; AH_Angle in_angle;
AH_Angle out_angle; AH_Angle out_angle;
AH_Point* next; /* next point in contour */ AH_Point* next; /* next point in contour */
AH_Point* prev; /* previous point in contour */ AH_Point* prev; /* previous point in contour */
}; };
/*************************************************************************** /*************************************************************************/
* /* */
* <Struct> /* <Struct> */
* AH_Segment /* AH_Segment */
* /* */
* <Description> /* <Description> */
* a structure used to describe an edge segment to the auto-hinter. A /* A structure used to describe an edge segment to the auto-hinter. */
* segment is simply a sequence of successive points located on the same /* A segment is simply a sequence of successive points located on the */
* horizontal or vertical "position", in a given direction. /* same horizontal or vertical `position', in a given direction. */
* /* */
* <Fields> /* <Fields> */
* flags :: segment edge flags ( straight, rounded.. ) /* flags :: The segment edge flags (straight, rounded, etc.). */
* dir :: segment direction /* */
* /* dir :: The segment direction. */
* first :: first point in segment /* */
* last :: last point in segment /* first :: The first point in the segment. */
* contour :: ptr to first point of segment's contour /* */
* /* last :: The last point in the segment. */
* pos :: segment position in font units /* */
* size :: segment size /* contour :: A pointer to the first point of the segment's */
* /* contour. */
* edge :: edge of current segment /* */
* edge_next :: next segment on same edge /* pos :: The segment position in font units. */
* /* */
* link :: the pairing segment for this edge /* size :: The segment size. */
* serif :: the primary segment for serifs /* */
* num_linked :: the number of other segments that link to this one /* edge :: The edge of the current segment. */
* /* */
* score :: used to score the segment when selecting them.. /* edge_next :: The next segment on the same edge. */
* /* */
*/ /* link :: The pairing segment for this edge. */
/* */
/* serif :: The primary segment for serifs. */
/* */
/* num_linked :: The number of other segments that link to this one. */
/* */
/* score :: Used to score the segment when selecting them. */
/* */
struct AH_Segment struct AH_Segment
{ {
AH_Edge_Flags flags; AH_Edge_Flags flags;
AH_Direction dir; AH_Direction dir;
AH_Point* first; /* first point in edge segment */ AH_Point* first; /* first point in edge segment */
AH_Point* last; /* last point in edge segment */ AH_Point* last; /* last point in edge segment */
AH_Point** contour; /* ptr to first point of segment's contour */ AH_Point** contour; /* ptr to first point of segment's contour */
FT_Pos pos; /* position of segment */ FT_Pos pos; /* position of segment */
FT_Pos min_coord; /* minimum coordinate of segment */ FT_Pos min_coord; /* minimum coordinate of segment */
FT_Pos max_coord; /* maximum coordinate of segment */ FT_Pos max_coord; /* maximum coordinate of segment */
AH_Edge* edge; AH_Edge* edge;
AH_Segment* edge_next; AH_Segment* edge_next;
AH_Segment* link; /* link segment */ AH_Segment* link; /* link segment */
AH_Segment* serif; /* primary segment for serifs */ AH_Segment* serif; /* primary segment for serifs */
FT_Pos num_linked; /* number of linked segments */ FT_Pos num_linked; /* number of linked segments */
FT_Int score; FT_Int score;
}; };
/*************************************************************************** /*************************************************************************/
* /* */
* <Struct> /* <Struct> */
* AH_Edge /* AH_Edge */
* /* */
* <Description> /* <Description> */
* a structure used to describe an edge, which really is a horizontal /* A structure used to describe an edge, which really is a horizontal */
* or vertical coordinate which will be hinted depending on the segments /* or vertical coordinate to be hinted depending on the segments */
* located on it.. /* located on it. */
* /* */
* <Fields> /* <Fields> */
* flags :: segment edge flags ( straight, rounded.. ) /* flags :: The segment edge flags (straight, rounded, etc.). */
* dir :: main segment direction on this edge /* */
* /* dir :: The main segment direction on this edge. */
* first :: first edge segment /* */
* last :: last edge segment /* first :: The first edge segment. */
* /* */
* fpos :: original edge position in font units /* last :: The last edge segment. */
* opos :: original scaled edge position /* */
* pos :: hinted edge position /* fpos :: The original edge position in font units. */
* /* */
* link :: the linked edge /* opos :: The original scaled edge position. */
* serif :: the serif edge /* */
* num_paired :: the number of other edges that pair to this one /* pos :: The hinted edge position. */
* /* */
* score :: used to score the edge when selecting them.. /* link :: The linked edge. */
* /* */
* blue_edge :: indicate the blue zone edge this edge is related to /* serif :: The serif edge. */
* only set for some of the horizontal edges in a Latin /* */
* font.. /* num_paired :: The number of other edges that pair to this one. */
* /* */
***************************************************************************/ /* score :: Used to score the edge when selecting them. */
/* */
/* blue_edge :: Indicate the blue zone edge this edge is related to. */
/* Only set for some of the horizontal edges in a Latin */
/* font. */
/* */
struct AH_Edge struct AH_Edge
{ {
AH_Edge_Flags flags; AH_Edge_Flags flags;
AH_Direction dir; AH_Direction dir;
AH_Segment* first; AH_Segment* first;
AH_Segment* last; AH_Segment* last;
FT_Pos fpos; FT_Pos fpos;
FT_Pos opos; FT_Pos opos;
FT_Pos pos; FT_Pos pos;
AH_Edge* link; AH_Edge* link;
AH_Edge* serif; AH_Edge* serif;
FT_Int num_linked; FT_Int num_linked;
FT_Int score; FT_Int score;
FT_Pos* blue_edge; FT_Pos* blue_edge;
}; };
/* an outline as seen by the hinter */ /* an outline as seen by the hinter */
typedef struct AH_Outline_ typedef struct AH_Outline_
{ {
FT_Memory memory; FT_Memory memory;
AH_Direction vert_major_dir; /* vertical major direction */ AH_Direction vert_major_dir; /* vertical major direction */
AH_Direction horz_major_dir; /* horizontal major direction */ AH_Direction horz_major_dir; /* horizontal major direction */
FT_Fixed x_scale; FT_Fixed x_scale;
FT_Fixed y_scale; FT_Fixed y_scale;
FT_Pos edge_distance_threshold; FT_Pos edge_distance_threshold;
FT_Int max_points; FT_Int max_points;
FT_Int num_points; FT_Int num_points;
AH_Point* points; AH_Point* points;
FT_Int max_contours; FT_Int max_contours;
FT_Int num_contours; FT_Int num_contours;
AH_Point** contours; AH_Point** contours;
FT_Int num_hedges; FT_Int num_hedges;
AH_Edge* horz_edges; AH_Edge* horz_edges;
FT_Int num_vedges; FT_Int num_vedges;
AH_Edge* vert_edges; AH_Edge* vert_edges;
FT_Int num_hsegments; FT_Int num_hsegments;
AH_Segment* horz_segments; AH_Segment* horz_segments;
FT_Int num_vsegments; FT_Int num_vsegments;
AH_Segment* vert_segments; AH_Segment* vert_segments;
} AH_Outline; } AH_Outline;
#define ah_blue_capital_top 0 /* THEZOCQS */
#define ah_blue_capital_bottom ( ah_blue_capital_top + 1 ) /* HEZLOCUS */
#define ah_blue_small_top ( ah_blue_capital_bottom + 1 ) /* xzroesc */
#define ah_blue_small_bottom ( ah_blue_small_top + 1 ) /* xzroesc */
#define ah_blue_small_minor ( ah_blue_small_bottom + 1 ) /* pqgjy */
#define ah_blue_max ( ah_blue_small_minor + 1 )
typedef enum AH_Blue_ typedef FT_Int AH_Blue;
{
ah_blue_capital_top, /* THEZOCQS */
ah_blue_capital_bottom, /* HEZLOCUS */
ah_blue_small_top, /* xzroesc */
ah_blue_small_bottom, /* xzroesc */
ah_blue_small_minor, /* pqgjy */
ah_blue_max
} AH_Blue;
typedef enum
{
ah_hinter_monochrome = 1,
ah_hinter_optimize = 2
} AH_Hinter_Flags;
/************************************************************************ #define ah_hinter_monochrome 1
* #define ah_hinter_optimize 2
* <Struct>
* AH_Globals
*
* <Description>
* Holds the global metrics for a given font face (be it in design
* units, or scaled pixel values)..
*
* <Fields>
* num_widths :: number of widths
* num_heights :: number of heights
* widths :: snap widths, including standard one
* heights :: snap height, including standard one
* blue_refs :: reference position of blue zones
* blue_shoots :: overshoot position of blue zones
*
************************************************************************/
typedef FT_Int AH_Hinter_Flags;
/*************************************************************************/
/* */
/* <Struct> */
/* AH_Globals */
/* */
/* <Description> */
/* Holds the global metrics for a given font face (be it in design */
/* units or scaled pixel values). */
/* */
/* <Fields> */
/* num_widths :: The number of widths. */
/* */
/* num_heights :: The number of heights. */
/* */
/* widths :: Snap widths, including standard one. */
/* */
/* heights :: Snap height, including standard one. */
/* */
/* blue_refs :: The reference positions of blue zones. */
/* */
/* blue_shoots :: The overshoot positions of blue zones. */
/* */
typedef struct AH_Globals_ typedef struct AH_Globals_
{ {
FT_Int num_widths; FT_Int num_widths;
FT_Int num_heights; FT_Int num_heights;
FT_Pos widths [ AH_MAX_WIDTHS ]; FT_Pos widths [AH_MAX_WIDTHS];
FT_Pos heights[ AH_MAX_HEIGHTS ]; FT_Pos heights[AH_MAX_HEIGHTS];
FT_Pos blue_refs [ ah_blue_max ]; FT_Pos blue_refs [ah_blue_max];
FT_Pos blue_shoots[ ah_blue_max ]; FT_Pos blue_shoots[ah_blue_max];
} AH_Globals; } AH_Globals;
/************************************************************************ /*************************************************************************/
* /* */
* <Struct> /* <Struct> */
* AH_Face_Globals /* AH_Face_Globals */
* /* */
* <Description> /* <Description> */
* Holds the complete global metrics for a given font face (i.e. the /* Holds the complete global metrics for a given font face (i.e., the */
* design units version + a scaled version + the current scales used) /* design units version + a scaled version + the current scales */
* /* used). */
* <Fields> /* */
* face :: handle to source face object /* <Fields> */
* design :: globals in font design units /* face :: A handle to the source face object */
* scaled :: scaled globals in sub-pixel values /* */
* x_scale :: current horizontal scale /* design :: The globals in font design units. */
* y_scale :: current vertical scale /* */
* /* scaled :: Scaled globals in sub-pixel values. */
************************************************************************/ /* */
/* x_scale :: The current horizontal scale. */
typedef struct AH_Face_Globals_ /* */
/* y_scale :: The current vertical scale. */
/* */
typedef struct AH_Face_Globals_
{ {
FT_Face face; FT_Face face;
AH_Globals design; AH_Globals design;
@ -419,12 +467,10 @@
} AH_Face_Globals; } AH_Face_Globals;
typedef struct AH_Hinter
typedef struct AH_Hinter
{ {
FT_Memory memory; FT_Memory memory;
FT_Long flags; AH_Hinter_Flags flags;
FT_Int algorithm; FT_Int algorithm;
FT_Face face; FT_Face face;
@ -439,4 +485,8 @@
} AH_Hinter; } AH_Hinter;
#endif /* AGTYPES_H */
#endif /* AHTYPES_H */
/* END */

View File

@ -2,22 +2,23 @@
/* */ /* */
/* autohint.c */ /* autohint.c */
/* */ /* */
/* Automatic Hinting wrapper. */ /* Automatic Hinting wrapper (body only). */
/* */ /* */
/* Copyright 2000: Catharon Productions Inc. */ /* Copyright 2000 Catharon Productions Inc. */
/* Author: David Turner */ /* Author: David Turner */
/* */ /* */
/* This file is part of the Catharon Typography Project and shall only */ /* This file is part of the Catharon Typography Project and shall only */
/* be used, modified, and distributed under the terms of the Catharon */ /* be used, modified, and distributed under the terms of the Catharon */
/* Open Source License that should come with this file under the name */ /* Open Source License that should come with this file under the name */
/* "CatharonLicense.txt". By continuing to use, modify, or distribute */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */ /* this file you indicate that you have read the license and */
/* understand and accept it fully. */ /* understand and accept it fully. */
/* */ /* */
/* Note that this license is compatible with the FreeType license */ /* Note that this license is compatible with the FreeType license. */
/* */ /* */
/***************************************************************************/ /***************************************************************************/
#define FT_MAKE_OPTION_SINGLE_OBJECT #define FT_MAKE_OPTION_SINGLE_OBJECT
#ifdef FT_FLAT_COMPILE #ifdef FT_FLAT_COMPILE
@ -38,3 +39,5 @@
#endif #endif
/* END */

View File

@ -1,3 +1,21 @@
#!/usr/bin/env python
#
#
# autohint math table builder
#
# Copyright 1996-2000 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.
import math import math
ag_pi = 256 ag_pi = 256
@ -5,50 +23,56 @@ ag_pi = 256
def print_arctan( atan_bits ): def print_arctan( atan_bits ):
atan_base = 1 << atan_bits atan_base = 1 << atan_bits
print "static AH_Angle ag_arctan[ 1L << AG_ATAN_BITS ] =" print " static AH_Angle ag_arctan[1L << AG_ATAN_BITS] ="
print "{" print " {"
count = 0 count = 0
line = "" line = " "
for n in range(atan_base): for n in range( atan_base ):
comma = "," comma = ","
if (n == atan_base-1): if ( n == atan_base - 1 ):
comma = "" comma = ""
angle = math.atan(n*1.0/atan_base)/math.pi*ag_pi angle = math.atan( n * 1.0 / atan_base ) / math.pi * ag_pi
line = line + " " + repr(int(angle+0.5)) + comma line = line + " " + repr( int( angle + 0.5 ) ) + comma
count = count+1; count = count + 1;
if (count == 8): if ( count == 8 ):
count = 0 count = 0
print line print line
line = "" line = " "
if (count >0): if ( count > 0 ):
print line print line
print "};" print " };"
# This routine is not used currently.
#
def print_sines(): def print_sines():
print "static FT_Fixed ah_sines[ AG_HALF_PI+1 ] =" print " static FT_Fixed ah_sines[AG_HALF_PI + 1] ="
print "{" print " {"
count = 0 count = 0
line = "" line = " "
for n in range(ag_pi/2): for n in range( ag_pi / 2 ):
sinus = math.sin(n*math.pi/ag_pi) sinus = math.sin( n * math.pi / ag_pi )
line = line + " " + repr(int(65536.0*sinus)) + "," line = line + " " + repr( int( 65536.0 * sinus ) ) + ","
count = count+1 count = count + 1
if (count == 8): if ( count == 8 ):
count = 0 count = 0
print line print line
line = "" line = " "
if (count > 0): if ( count > 0 ):
print line print line
print " 65536" print " 65536"
print "};" print " };"
print_arctan(8)
print_arctan( 8 )
print print
# END

View File

@ -3,28 +3,17 @@
# #
# Copyright 2000 Catharon Productions Inc.
# Author: David Turner
# #
# Copyright 2000: Catharon Productions Inc. # This file is part of the Catharon Typography Project and shall only
# Author: David Turner # be used, modified, and distributed under the terms of the Catharon
# Open Source License that should come with this file under the name
# `CatharonLicense.txt'. By continuing to use, modify, or distribute
# this file you indicate that you have read the license and
# understand and accept it fully.
# #
# This file is part of the Catharon Typography Project and shall only # Note that this license is compatible with the FreeType license.
# be used, modified, and distributed under the terms of the Catharon
# Open Source License that should come with this file under the name
# "CatharonLicense.txt". By continuing to use, modify, or distribute
# this file you indicate that you have read the license and
# understand and accept it fully.
#
# Note that this license is compatible with the FreeType license
#
#
# Copyright 1996-2000 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.
# AUTO driver directory # AUTO driver directory
@ -48,7 +37,9 @@ AUTO_DRV_SRC := $(AUTO_DIR_)ahangles.c \
# AUTO driver headers # AUTO driver headers
# #
AUTO_DRV_H := $(AUTO_DRV_SRC:%c=%h) AUTO_DRV_H := $(AUTO_DRV_SRC:%c=%h) \
$(AUTO_DIR_)ahloader.h \
$(AUTO_DIR_)ahtypes.h
# AUTO driver object(s) # AUTO driver object(s)

View File

@ -70,4 +70,5 @@ $(OBJ_)%.$O: $(T1_DIR_)%.c $(FREETYPE_H) $(T1_DRV_H)
DRV_OBJS_S += $(T1_DRV_OBJ_S) DRV_OBJS_S += $(T1_DRV_OBJ_S)
DRV_OBJS_M += $(T1_DRV_OBJ_M) DRV_OBJS_M += $(T1_DRV_OBJ_M)
# EOF # EOF