added auto-hinter module. Note that the code has been

cleaned up, and it seems a bug was introduced ???

I'll start checking this under Linux, as debugging is a lot
easier under this environment..
This commit is contained in:
David Turner 2000-07-19 20:02:14 +00:00
parent 6930b45f78
commit 3469d0d038
19 changed files with 5140 additions and 0 deletions

View File

@ -0,0 +1,123 @@
The Catharon Open Source LICENSE
----------------------------
2000-Jul-4
Copyright (C) 2000 by Catharon Productions, Inc.
Introduction
============
This license applies to source files distributed by Catharon
Productions, Inc. in several archive packages. This license
applies to all files found in such packages which do not fall
under their own explicit license.
This license was inspired by the BSD, Artistic, and IJG
(Independent JPEG Group) licenses, which all encourage inclusion
and use of free software in commercial and freeware products
alike. As a consequence, its main points are that:
o We don't promise that this software works. However, we are
interested in any kind of bug reports. (`as is' distribution)
o You can use this software for whatever you want, in parts or
full form, without having to pay us. (`royalty-free' usage)
o You may not pretend that you wrote this software. If you use
it, or only parts of it, in a program, you must acknowledge
somewhere in your documentation that you have used the
Catharon Code. (`credits')
We specifically permit and encourage the inclusion of this
software, with or without modifications, in commercial products.
We disclaim all warranties covering the packages distributed by
Catharon Productions, Inc. and assume no liability related to
their use.
Legal Terms
===========
0. Definitions
--------------
Throughout this license, the terms `Catharon Package', `package',
and `Catharon Code' refer to the set of files originally
distributed by Catharon Productions, Inc.
`You' refers to the licensee, or person using the project, where
`using' is a generic term including compiling the project's source
code as well as linking it to form a `program' or `executable'.
This program is referred to as `a program using one of the
Catharon Packages'.
This license applies to all files distributed in the original
Catharon Package(s), including all source code, binaries and
documentation, unless otherwise stated in the file in its
original, unmodified form as distributed in the original archive.
If you are unsure whether or not a particular file is covered by
this license, you must contact us to verify this.
The Catharon Packages are copyright (C) 2000 by Catharon
Productions, Inc. All rights reserved except as specified below.
1. No Warranty
--------------
THE CATHARON PACKAGES ARE PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OF OR THE INABILITY TO
USE THE CATHARON PACKAGE.
2. Redistribution
-----------------
This license grants a worldwide, royalty-free, perpetual and
irrevocable right and license to use, execute, perform, compile,
display, copy, create derivative works of, distribute and
sublicense the Catharon Packages (in both source and object code
forms) and derivative works thereof for any purpose; and to
authorize others to exercise some or all of the rights granted
herein, subject to the following conditions:
o Redistribution of source code must retain this license file
(`license.txt') unaltered; any additions, deletions or changes
to the original files must be clearly indicated in
accompanying documentation. The copyright notices of the
unaltered, original files must be preserved in all copies of
source files.
o Redistribution in binary form must provide a disclaimer that
states that the software is based in part on the work of
Catharon Productions, Inc. in the distribution documentation.
These conditions apply to any software derived from or based on
the Catharon Packages, not just the unmodified files. If you use
our work, you must acknowledge us. However, no fee need be paid
to us.
3. Advertising
--------------
Neither Catharon Productions, Inc. and contributors nor you shall
use the name of the other for commercial, advertising, or
promotional purposes without specific prior written permission.
We suggest, but do not require, that you use the following phrase
to refer to this software in your documentation: 'this software is
based in part on the Catharon Typography Project'.
As you have not signed this license, you are not required to
accept it. However, as the Catharon Packages are copyrighted
material, only this license, or another one contracted with the
authors, grants you the right to use, distribute, and modify it.
Therefore, by using, distributing, or modifying the Catharon
Packages, you indicate that you understand and accept all the
terms of this license.
--- end of license.txt ---

125
src/autohint/ahangles.c Normal file
View File

@ -0,0 +1,125 @@
/***************************************************************************/
/* */
/* ahangles.h */
/* */
/* a routine used to compute vector angles with limited accuracy */
/* and very high speed. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifdef FT_FLAT_COMPILE
#include "ahangles.h"
#else
#include <autohint/ahangles.h>
#endif
/* the following two tables are automatically generated with */
/* the "mather.py" Python script.. */
static const AH_Angle ah_arctan[ 1L << AH_ATAN_BITS ] =
{
0, 0, 1, 1, 1, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 5,
5, 5, 6, 6, 6, 7, 7, 7,
8, 8, 8, 9, 9, 9, 10, 10,
10, 10, 11, 11, 11, 12, 12, 12,
13, 13, 13, 14, 14, 14, 14, 15,
15, 15, 16, 16, 16, 17, 17, 17,
18, 18, 18, 18, 19, 19, 19, 20,
20, 20, 21, 21, 21, 21, 22, 22,
22, 23, 23, 23, 24, 24, 24, 24,
25, 25, 25, 26, 26, 26, 26, 27,
27, 27, 28, 28, 28, 28, 29, 29,
29, 30, 30, 30, 30, 31, 31, 31,
31, 32, 32, 32, 33, 33, 33, 33,
34, 34, 34, 34, 35, 35, 35, 35,
36, 36, 36, 36, 37, 37, 37, 38,
38, 38, 38, 39, 39, 39, 39, 40,
40, 40, 40, 41, 41, 41, 41, 42,
42, 42, 42, 42, 43, 43, 43, 43,
44, 44, 44, 44, 45, 45, 45, 45,
46, 46, 46, 46, 46, 47, 47, 47,
47, 48, 48, 48, 48, 48, 49, 49,
49, 49, 50, 50, 50, 50, 50, 51,
51, 51, 51, 51, 52, 52, 52, 52,
52, 53, 53, 53, 53, 53, 54, 54,
54, 54, 54, 55, 55, 55, 55, 55,
56, 56, 56, 56, 56, 57, 57, 57,
57, 57, 57, 58, 58, 58, 58, 58,
59, 59, 59, 59, 59, 59, 60, 60,
60, 60, 60, 61, 61, 61, 61, 61,
61, 62, 62, 62, 62, 62, 62, 63,
63, 63, 63, 63, 63, 64, 64, 64
};
LOCAL_FUNC
AH_Angle ah_angle( FT_Vector* v )
{
FT_Pos dx, dy;
AH_Angle angle;
dx = v->x;
dy = v->y;
/* check trivial cases */
if (dy == 0)
{
angle = 0;
if (dx < 0)
angle = AH_PI;
return angle;
}
else if (dx == 0)
{
angle = AH_HALF_PI;
if (dy < 0)
angle = -AH_HALF_PI;
return angle;
}
angle = 0;
if ( dx < 0 )
{
dx = -v->x;
dy = -v->y;
angle = AH_PI;
}
if ( dy < 0 )
{
FT_Pos tmp;
tmp = dx;
dx = -dy;
dy = tmp;
angle -= AH_HALF_PI;
}
if (dx == 0 && dy == 0)
return 0;
if (dx == dy)
angle += AH_PI/4;
else if (dx > dy)
angle += ah_arctan[ FT_DivFix( dy, dx ) >> (16-AH_ATAN_BITS) ];
else
angle += AH_HALF_PI - ah_arctan[ FT_DivFix( dx, dy ) >> (16-AH_ATAN_BITS) ];
if (angle > AH_PI)
angle -= AH_2PI;
return angle;
}

47
src/autohint/ahangles.h Normal file
View File

@ -0,0 +1,47 @@
/***************************************************************************/
/* */
/* ahangles.h */
/* */
/* a routine used to compute vector angles with limited accuracy */
/* and very high speed. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGANGLES_H
#define AGANGLES_H
#ifdef FT_FLAT_COMPILE
#include "ahtypes.h"
#else
#include <autohint/ahtypes.h>
#endif
#include <freetype/internal/ftobjs.h>
/* PI expressed in ah_angles - we don't really need an important */
/* precision, so 256 should be enough.. */
#define AH_PI 256
#define AH_2PI (AH_PI*2)
#define AH_HALF_PI (AH_PI/2)
#define AH_2PIMASK (AH_2PI-1)
/* the number of bits to use to express an arc tangent */
/* see the structure of the lookup table.. */
#define AH_ATAN_BITS 8
LOCAL_DEF const AH_Angle ah_arctan[ 1L << AH_ATAN_BITS ];
LOCAL_DEF AH_Angle ah_angle( FT_Vector* v );
#endif /* AGANGLES_H */

365
src/autohint/ahglobal.c Normal file
View File

@ -0,0 +1,365 @@
/***************************************************************************/
/* */
/* ahglobal.c */
/* */
/* routines used to compute global metrics automatically */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifdef FT_FLAT_COMPILE
#include "ahglobal.h"
#include "ahglyph.h"
#else
#include <autohint/ahglobal.h>
#include <autohint/ahglyph.h>
#endif
#define MAX_TEST_CHARACTERS 12
static const char* blue_chars[ ah_blue_max ] =
{
"THEZOCQS",
"HEZLOCUS",
"xzroesc",
"xzroesc",
"pqgjy"
};
/* simple insertion sort */
static
void sort_values( FT_Int count, FT_Pos* table )
{
FT_Int i, j, swap;
for ( i = 1; i < count; i++ )
{
for ( j = i; j > 1; j-- )
{
if ( table[j] > table[j-1] )
break;
swap = table[j];
table[j] = table[j-1];
table[j-1] = swap;
}
}
}
static
FT_Error ah_hinter_compute_blues( AH_Hinter* hinter )
{
AH_Blue blue;
AH_Globals* globals = &hinter->globals->design;
FT_Pos flats [ MAX_TEST_CHARACTERS ];
FT_Pos rounds[ MAX_TEST_CHARACTERS ];
FT_Int num_flats;
FT_Int num_rounds;
FT_Face face;
FT_GlyphSlot glyph;
FT_Error error;
FT_CharMap charmap;
face = hinter->face;
glyph = face->glyph;
/* save current charmap */
charmap = face->charmap;
/* do we have a Unicode charmap in there ?? */
error = FT_Select_Charmap( face, ft_encoding_unicode );
if (error) goto Exit;
/* we compute the blues simply by loading each character from the */
/* 'blue_chars[blues]' string, then compute its top-most and bottom-most */
/* points */
AH_LOG(( "blue zones computation\n" ));
AH_LOG(( "------------------------------------------------\n" ));
for ( blue = (AH_Blue)0; blue < ah_blue_max; blue++ )
{
const char* p = blue_chars[blue];
const char* limit = p + MAX_TEST_CHARACTERS;
FT_Pos *blue_ref, *blue_shoot;
AH_LOG(( "blue %3d : ", (int)blue ));
num_flats = 0;
num_rounds = 0;
for ( ; p < limit; p++ )
{
FT_UInt glyph_index;
FT_Vector* extremum;
FT_Vector* points;
FT_Vector* point_limit;
FT_Vector* point;
FT_Bool round;
/* exit if we reach the end of the string */
if (!*p) break;
AH_LOG(( "'%c'", *p ));
/* load the character in the face - skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
if (glyph_index == 0) continue;
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if (error || glyph->outline.n_points <= 0) continue;
/* now compute min or max point indices and coordinates */
points = glyph->outline.points;
point_limit = points + glyph->outline.n_points;
point = points;
extremum = point;
point++;
if ( AH_IS_TOP_BLUE(blue) )
{
for ( ; point < point_limit; point++ )
if ( point->y > extremum->y )
extremum = point;
}
else
{
for ( ; point < point_limit; point++ )
if ( point->y < extremum->y )
extremum = point;
}
AH_LOG(( "%5d", (int)extremum->y ));
/* now, see if the point belongs to a straight or round segment */
/* we first need to find in which contour the extremum lies then */
/* see its previous and next points.. */
{
FT_Int index = extremum - points;
FT_Int n;
FT_Int first = 0;
FT_Int last, prev, next, end;
FT_Pos dist;
last = -1;
first = 0;
for ( n = 0; n < glyph->outline.n_contours; n++ )
{
end = glyph->outline.contours[n];
if ( end >= index )
{
last = end;
break;
}
first = end+1;
}
/* XXX : should never happen !!! */
if ( last < 0 )
continue;
/* now look for the previous and next points that are not on the */
/* same Y coordinate. Threshold the "closeness" .. */
prev = index;
next = prev;
do
{
if (prev > first) prev--;
else prev = last;
dist = points[prev].y - extremum->y;
if ( dist < -5 || dist > 5 )
break;
} while (prev != index);
do
{
if (next < last) next++;
else next = first;
dist = points[next].y - extremum->y;
if ( dist < -5 || dist > 5 )
break;
} while (next != index);
/* now, set the "round" flag depending on the segment's kind */
round = FT_CURVE_TAG(glyph->outline.tags[prev]) != FT_Curve_Tag_On ||
FT_CURVE_TAG(glyph->outline.tags[next]) != FT_Curve_Tag_On ;
AH_LOG(( "%c ", round ? 'r' : 'f' ));
}
if (round)
rounds[ num_rounds++ ] = extremum->y;
else
flats[ num_flats++ ] = extremum->y;
}
AH_LOG(( "\n" ));
/* we have computed the contents of the 'rounds' and 'flats' tables */
/* now determine the reference and overshoot position of the blue */
/* we simply take the median value after a simple short.. */
sort_values( num_rounds, rounds );
sort_values( num_flats, flats );
blue_ref = globals->blue_refs + blue;
blue_shoot = globals->blue_shoots + blue;
if ( num_flats == 0 && num_rounds == 0 )
{
*blue_ref = -10000;
*blue_shoot = -10000;
}
else if ( num_flats == 0 )
{
*blue_ref =
*blue_shoot = rounds[ num_rounds/2 ];
}
else if ( num_rounds == 0 )
{
*blue_ref =
*blue_shoot = flats[ num_flats/2 ];
}
else
{
*blue_ref = flats[ num_flats/2 ];
*blue_shoot = rounds[ num_rounds/2 ];
}
/* there are sometimes problems, when the overshoot position of top */
/* zones is under its reference position, or the opposite for bottom */
/* zones. We must thus check everything there.. and correct the errors */
if ( *blue_shoot != *blue_ref )
{
FT_Pos ref = *blue_ref;
FT_Pos shoot = *blue_shoot;
FT_Bool over_ref = ( shoot > ref );
if ( AH_IS_TOP_BLUE(blue) ^ over_ref )
*blue_shoot = *blue_ref = (shoot+ref)/2;
}
AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
}
/* reset original face charmap */
FT_Set_Charmap( face, charmap );
error = 0;
Exit:
return error;
}
static
FT_Error ah_hinter_compute_widths( AH_Hinter* hinter )
{
/* scan the array of segments in each direction */
AH_Outline* outline = hinter->glyph;
AH_Segment* segments;
AH_Segment* limit;
AH_Globals* globals = &hinter->globals->design;
FT_Pos* widths;
FT_Int dimension;
FT_Int* p_num_widths;
FT_Error error = 0;
FT_Pos edge_distance_threshold = 32000;
globals->num_widths = 0;
globals->num_heights = 0;
/* for now, compute the standard width and height from the "o" character */
/* I started computing the stem width of the "i" and the stem height of */
/* the "-", but it wasn't too good.. Moreover, we now have a single */
/* character that gives us standard width and height */
{
FT_UInt glyph_index;
glyph_index = FT_Get_Char_Index( hinter->face, 'o' );
if (glyph_index == 0) return 0;
error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
if (error) goto Exit;
error = ah_outline_load( hinter->glyph, hinter->face );
if (error) goto Exit;
ah_outline_compute_segments( hinter->glyph );
ah_outline_link_segments( hinter->glyph );
}
segments = outline->horz_segments;
limit = segments + outline->num_hsegments;
widths = globals->heights;
p_num_widths = &globals->num_heights;
for ( dimension = 1; dimension >= 0; dimension-- )
{
AH_Segment* seg = segments;
AH_Segment* link;
FT_Int num_widths = 0;
for ( ; seg < limit; seg++ )
{
link = seg->link;
/* we only consider the stem segments there ! */
if (link && link->link == seg && link > seg)
{
FT_Int dist;
dist = seg->pos - link->pos;
if (dist < 0) dist = -dist;
if ( num_widths < 12 )
widths[ num_widths++ ] = dist;
}
}
sort_values( num_widths, widths );
*p_num_widths = num_widths;
/* we will now try to find the smallest width */
if (num_widths > 0 && widths[0] < edge_distance_threshold )
edge_distance_threshold = widths[0];
segments = outline->vert_segments;
limit = segments + outline->num_vsegments;
widths = globals->widths;
p_num_widths = &globals->num_widths;
}
/* now, compute the edge distance threshold as a fraction of the */
/* smallest width in the font.. Set it in "hinter.glyph" too !! */
if ( edge_distance_threshold == 32000)
edge_distance_threshold = 50;
/* let's try 20% */
hinter->glyph->edge_distance_threshold = edge_distance_threshold/5;
Exit:
return error;
}
LOCAL_FUNC
FT_Error ah_hinter_compute_globals( AH_Hinter* hinter )
{
return ah_hinter_compute_widths( hinter ) ||
ah_hinter_compute_blues ( hinter );
}

38
src/autohint/ahglobal.h Normal file
View File

@ -0,0 +1,38 @@
/***************************************************************************/
/* */
/* ahglobal.h */
/* */
/* routines used to compute global metrics automatically */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGGLOBAL_H
#define AGGLOBAL_H
#ifdef FT_FLAT_COMPILE
#include "ahtypes.h"
#else
#include <autohint/ahtypes.h>
#endif
#include <freetype/internal/ftobjs.h> /* for LOCAL_DEF/LOCAL_FUNC */
#define AH_IS_TOP_BLUE(b) ( (b) == ah_blue_capital_top || \
(b) == ah_blue_small_top )
/* compute global metrics automatically */
LOCAL_DEF
FT_Error ah_hinter_compute_globals( AH_Hinter* hinter );
#endif /* AGGLOBAL_H */

1192
src/autohint/ahglyph.c Normal file

File diff suppressed because it is too large Load Diff

79
src/autohint/ahglyph.h Normal file
View File

@ -0,0 +1,79 @@
/***************************************************************************/
/* */
/* ahglyph.h */
/* */
/* routines used to load and analyze a given glyph before hinting */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGGLYPH_H
#define AGGLYPH_H
#ifdef FT_FLAT_COMPILE
#include "ahtypes.h"
#else
#include <autohint/ahtypes.h>
#endif
typedef enum AH_UV_
{
ah_uv_fxy,
ah_uv_fyx,
ah_uv_oxy,
ah_uv_oyx,
ah_uv_ox,
ah_uv_oy,
ah_uv_yx,
ah_uv_xy /* should always be last !! */
} AH_UV;
LOCAL_DEF
void ah_setup_uv( AH_Outline* outline,
AH_UV source );
/* AH_Outline functions - they should be typically called in this order */
LOCAL_DEF
FT_Error ah_outline_new( FT_Memory memory, AH_Outline* *aoutline );
LOCAL_DEF
FT_Error ah_outline_load( AH_Outline* outline, FT_Face face );
LOCAL_DEF
void ah_outline_compute_segments( AH_Outline* outline );
LOCAL_DEF
void ah_outline_link_segments( AH_Outline* outline );
LOCAL_DEF
void ah_outline_detect_features( AH_Outline* outline );
LOCAL_DEF
void ah_outline_compute_blue_edges( AH_Outline* outline,
AH_Face_Globals* globals );
LOCAL_DEF
void ah_outline_scale_blue_edges( AH_Outline* outline,
AH_Face_Globals* globals );
LOCAL_DEF
void ah_outline_save( AH_Outline* outline, AH_Loader* loader );
LOCAL_DEF
void ah_outline_done( AH_Outline* outline );
#endif /* AGGLYPH_H */

1293
src/autohint/ahhint.c Normal file

File diff suppressed because it is too large Load Diff

65
src/autohint/ahhint.h Normal file
View File

@ -0,0 +1,65 @@
/***************************************************************************/
/* */
/* ahhint.h */
/* */
/* Glyph hinter declarations */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGHINT_H
#define AGHINT_H
#ifdef FT_FLAT_COMPILE
#include "ahglobal.h"
#else
#include <autohint/ahglobal.h>
#endif
#define AH_HINT_DEFAULT 0
#define AH_HINT_NO_ALIGNMENT 1
#define AH_HINT_NO_HORZ_EDGES 0x20000
#define AH_HINT_NO_VERT_EDGES 0x40000
/* create a new empty hinter object */
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_GlyphSlot slot,
FT_Size size,
FT_UInt glyph_index,
FT_Int load_flags );
/* finalise a hinter object */
extern
void ah_hinter_done( AH_Hinter* hinter );
LOCAL_DEF
void ah_hinter_done_face_globals( AH_Face_Globals* globals );
extern
void ah_hinter_get_global_hints( AH_Hinter* hinter,
FT_Face face,
void* *global_hints,
long *global_len );
extern
void ah_hinter_done_global_hints( AH_Hinter* hinter,
void* global_hints );
#endif /* AGHINT_H */

103
src/autohint/ahloader.h Normal file
View File

@ -0,0 +1,103 @@
/***************************************************************************/
/* */
/* ahloader.h */
/* */
/* Glyph loader implementation for the auto-hinting module */
/* This defines the AG_GlyphLoader type in two different ways: */
/* */
/* - when the module is compiled within FreeType 2, the type */
/* 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 */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGLOADER_H
#define AGLOADER_H
#ifdef _STANDALONE_
typedef struct AH_GlyphLoad_
{
FT_Outline outline; /* outline */
FT_UInt num_subglyphs; /* number of subglyphs */
FT_SubGlyph* subglyphs; /* subglyphs */
FT_Vector* extra_points; /* extra points table.. */
} AH_GlyphLoad;
struct AH_GlyphLoader_
{
FT_Memory memory;
FT_UInt max_points;
FT_UInt max_contours;
FT_UInt max_subglyphs;
FT_Bool use_extra;
AH_GlyphLoad base;
AH_GlyphLoad current;
void* other; /* for possible future extension ? */
};
LOCAL_DEF FT_Error AH_GlyphLoader_New( FT_Memory memory,
AH_GlyphLoader* *aloader );
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_Reset( AH_GlyphLoader* loader );
LOCAL_DEF void AH_GlyphLoader_Rewind( AH_GlyphLoader* loader );
LOCAL_DEF FT_Error AH_GlyphLoader_Check_Points( AH_GlyphLoader* loader,
FT_UInt n_points,
FT_UInt n_contours );
LOCAL_DEF 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_Add( AH_GlyphLoader* loader );
LOCAL_DEF FT_Error AH_GlyphLoader_Copy_Points( AH_GlyphLoader* target,
FT_GlyphLoader* source );
#else
#include <freetype/internal/ftobjs.h>
#define AH_Load FT_GlyphLoad
#define AH_Loader FT_GlyphLoader
#define ah_loader_new FT_GlyphLoader_New
#define ah_loader_done FT_GlyphLoader_Done
#define ah_loader_reset FT_GlyphLoader_Reset
#define ah_loader_rewind FT_GlyphLoader_Rewind
#define ah_loader_create_extra FT_GlyphLoader_Create_Extra
#define ah_loader_check_points FT_GlyphLoader_Check_Points
#define ah_loader_check_subglyphs FT_GlyphLoader_Check_Subglyphs
#define ah_loader_prepare FT_GlyphLoader_Prepare
#define ah_loader_add FT_GlyphLoader_Add
#define ah_loader_copy_points FT_GlyphLoader_Copy_Points
#endif
#endif /* AGLOADER_H */

111
src/autohint/ahmodule.c Normal file
View File

@ -0,0 +1,111 @@
/***************************************************************************/
/* */
/* ahmodule.c */
/* */
/* Auto-hinting module implementation */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#include <freetype/ftmodule.h>
#ifdef FT_FLAT_COMPILE
#include "ahhint.h"
#else
#include <autohint/ahhint.h>
#endif
typedef struct FT_AutoHinterRec_
{
FT_ModuleRec root;
AH_Hinter* hinter;
} FT_AutoHinterRec;
static
FT_Error ft_autohinter_init( FT_AutoHinter module )
{
return ah_hinter_new( module->root.library, &module->hinter );
}
static
void ft_autohinter_done( FT_AutoHinter module )
{
ah_hinter_done( module->hinter );
}
static
FT_Error ft_autohinter_load( FT_AutoHinter module,
FT_GlyphSlot slot,
FT_Size size,
FT_UInt glyph_index,
FT_ULong load_flags )
{
return ah_hinter_load_glyph( module->hinter,
slot, size, glyph_index, load_flags );
}
static
void ft_autohinter_reset( FT_AutoHinter module,
FT_Face face )
{
UNUSED(module);
if (face->autohint.data)
ah_hinter_done_face_globals( face->autohint.data );
}
static
void ft_autohinter_get_globals( FT_AutoHinter module,
FT_Face face,
void* *global_hints,
long *global_len )
{
ah_hinter_get_global_hints( module->hinter, face,
global_hints, global_len );
}
static
void ft_autohinter_done_globals( FT_AutoHinter module,
void* global_hints )
{
ah_hinter_done_global_hints( module->hinter, global_hints );
}
static
const FT_AutoHinter_Interface autohinter_interface =
{
ft_autohinter_reset,
ft_autohinter_load,
ft_autohinter_get_globals,
ft_autohinter_done_globals
};
const FT_Module_Class autohint_module_class =
{
ft_module_hinter,
sizeof( FT_AutoHinterRec ),
"autohinter",
0x10000, /* version 1.0 of the autohinter */
0x20000, /* requires FreeType 2.0 or above */
(const void*)&autohinter_interface,
(FT_Module_Constructor) ft_autohinter_init,
(FT_Module_Destructor) ft_autohinter_done,
(FT_Module_Requester) 0
};

27
src/autohint/ahmodule.h Normal file
View File

@ -0,0 +1,27 @@
/***************************************************************************/
/* */
/* ahmodule.h */
/* */
/* Auto-hinting module declaration */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AHMODULE_H
#define AHMODULE_H
#include <freetype/ftmodule.h>
FT_EXPORT_VAR(const FT_Module_Class) autohint_module_class;
#endif /* AHMODULE_H */

808
src/autohint/ahoptim.c Normal file
View File

@ -0,0 +1,808 @@
/***************************************************************************/
/* */
/* FreeType Auto-Gridder Outline Optimisation */
/* */
/* 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. */
/* */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#include <freetype/internal/ftobjs.h> /* for ALLOC_ARRAY and FREE */
#ifdef FT_FLAT_COMPILE
#include "ahoptim.h"
#else
#include <autohint/ahoptim.h>
#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
#undef LOG
#ifdef DEBUG_OPTIM
#define LOG(x) optim_log##x
#else
#define LOG(x)
#endif
#ifdef DEBUG_OPTIM
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#define FLOAT(x) ((float)((x)/64.0))
static
void optim_log( const char* fmt, ... )
{
va_list ap;
va_start( ap, fmt );
vprintf( fmt, ap );
va_end( ap );
}
#endif
#ifdef DEBUG_OPTIM
static
void AH_Dump_Stems( AH_Optimizer* optimizer )
{
int n;
AH_Stem* stem;
stem = optimizer->stems;
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",
optimizer->vertical ? 'V' : 'H', n,
FLOAT(stem->edge1->opos), FLOAT(stem->edge2->opos),
FLOAT(stem->edge1->pos), FLOAT(stem->edge2->pos),
FLOAT(stem->min_pos), FLOAT(stem->max_pos),
FLOAT(stem->force), FLOAT(stem->velocity) ));
}
}
static
void AH_Dump_Stems2( AH_Optimizer* optimizer )
{
int n;
AH_Stem* stem;
stem = optimizer->stems;
for ( n = 0; n < optimizer->num_stems; n++, stem++ )
{
LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n",
optimizer->vertical ? 'V' : 'H', n,
FLOAT(stem->pos),
FLOAT(stem->min_pos), FLOAT(stem->max_pos),
FLOAT(stem->force), FLOAT(stem->velocity) ));
}
}
static
void AH_Dump_Springs( AH_Optimizer* optimizer )
{
int n;
AH_Spring* spring;
AH_Stem* stems;
spring = optimizer->springs;
stems = optimizer->stems;
LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' ));
for ( n = 0; n < optimizer->num_springs; n++, spring++ )
{
LOG(( " [%d-%d:%.1f:%1.f:%.1f]", spring->stem1 - stems, spring->stem2 - stems,
FLOAT(spring->owidth),
FLOAT(spring->stem2->pos-(spring->stem1->pos+spring->stem1->width)),
FLOAT(spring->tension) ));
}
LOG(( "\n" ));
}
#endif
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/
/**** ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
static
int valid_stem_segments( AH_Segment* seg1, AH_Segment* seg2 )
{
return seg1->serif == 0 && seg2 && seg2->link == seg1 && seg1->pos < seg2->pos &&
seg1->min_coord <= seg2->max_coord &&
seg2->min_coord <= seg1->max_coord;
}
/* compute all stems in an outline */
static
int optim_compute_stems( AH_Optimizer* optimizer )
{
AH_Outline* outline = optimizer->outline;
FT_Fixed scale;
FT_Memory memory = optimizer->memory;
FT_Error error = 0;
FT_Int dimension;
AH_Edge* edges;
AH_Edge* edge_limit;
AH_Stem** p_stems;
FT_Int* p_num_stems;
edges = outline->horz_edges;
edge_limit = edges + outline->num_hedges;
scale = outline->y_scale;
p_stems = &optimizer->horz_stems;
p_num_stems = &optimizer->num_hstems;
for ( dimension = 1; dimension >= 0; dimension-- )
{
AH_Stem* stems = 0;
FT_Int num_stems = 0;
AH_Edge* edge;
/* first of all, count the number of stems in this direction */
for ( edge = edges; edge < edge_limit; edge++ )
{
AH_Segment* seg = edge->first;
do
{
if (valid_stem_segments( seg, seg->link ))
num_stems++;
seg = seg->edge_next;
} while (seg != edge->first);
}
/* now allocate the stems and build their table */
if (num_stems > 0)
{
AH_Stem* stem;
if ( ALLOC_ARRAY( stems, num_stems, AH_Stem ) )
goto Exit;
stem = stems;
for ( edge = edges; edge < edge_limit; edge++ )
{
AH_Segment* seg = edge->first;
AH_Segment* seg2;
do
{
seg2 = seg->link;
if (valid_stem_segments(seg,seg2))
{
AH_Edge* edge1 = seg->edge;
AH_Edge* edge2 = seg2->edge;
stem->edge1 = edge1;
stem->edge2 = edge2;
stem->opos = edge1->opos;
stem->pos = edge1->pos;
stem->owidth = edge2->opos - edge1->opos;
stem->width = edge2->pos - edge1->pos;
/* compute min_coord and max_coord */
{
FT_Pos min_coord = seg->min_coord;
FT_Pos max_coord = seg->max_coord;
if (seg2->min_coord > min_coord)
min_coord = seg2->min_coord;
if (seg2->max_coord < max_coord)
max_coord = seg2->max_coord;
stem->min_coord = min_coord;
stem->max_coord = max_coord;
}
/* compute minimum and maximum positions for stem */
/* note that the left-most/bottom-most stem has always */
/* a fixed position.. */
if (stem == stems || edge1->blue_edge || edge2->blue_edge)
{
/* this stem cannot move, it is snapped to a blue edge */
stem->min_pos = stem->pos;
stem->max_pos = stem->pos;
}
else
{
/* this edge can move, compute its min and max positions */
FT_Pos pos1 = stem->opos;
FT_Pos pos2 = pos1 + stem->owidth - stem->width;
FT_Pos min1 = (pos1 & -64);
FT_Pos min2 = (pos2 & -64);
stem->min_pos = min1;
stem->max_pos = min1+64;
if (min2 < min1)
stem->min_pos = min2;
else
stem->max_pos = min2+64;
/* XXX : just to see what it does */
stem->max_pos += 64;
/* just for the case where direct hinting did some incredible */
/* things (e.g. blue edge shifts..) */
if (stem->min_pos > stem->pos)
stem->min_pos = stem->pos;
if (stem->max_pos < stem->pos)
stem->max_pos = stem->pos;
}
stem->velocity = 0;
stem->force = 0;
stem++;
}
seg = seg->edge_next;
}
while (seg != edge->first);
}
}
*p_stems = stems;
*p_num_stems = num_stems;
edges = outline->vert_edges;
edge_limit = edges + outline->num_vedges;
scale = outline->x_scale;
p_stems = &optimizer->vert_stems;
p_num_stems = &optimizer->num_vstems;
}
Exit:
#ifdef DEBUG_OPTIM
AH_Dump_Stems(optimizer);
#endif
return error;
}
/* returns the spring area between two stems, 0 if none */
static
FT_Pos stem_spring_area( AH_Stem* stem1, AH_Stem* stem2 )
{
FT_Pos area1 = stem1->max_coord - stem1->min_coord;
FT_Pos area2 = stem2->max_coord - stem2->min_coord;
FT_Pos min = stem1->min_coord;
FT_Pos max = stem1->max_coord;
FT_Pos area;
/* order stems */
if (stem2->opos <= stem1->opos + stem1->owidth)
return 0;
if (min < stem2->min_coord)
min = stem2->min_coord;
if (max < stem2->max_coord)
max = stem2->max_coord;
area = (max-min);
if ( 2*area < area1 && 2*area < area2 )
area = 0;
return area;
}
/* compute all springs in an outline */
static
int optim_compute_springs( AH_Optimizer* optimizer )
{
/* basically, a spring exists between two stems if most of their */
/* surface is aligned.. */
FT_Memory memory = optimizer->memory;
AH_Stem* stems;
AH_Stem* stem_limit;
AH_Stem* stem;
int dimension;
int error = 0;
FT_Int* p_num_springs;
AH_Spring** p_springs;
stems = optimizer->horz_stems;
stem_limit = stems + optimizer->num_hstems;
p_springs = &optimizer->horz_springs;
p_num_springs = &optimizer->num_hsprings;
for ( dimension = 1; dimension >= 0; dimension-- )
{
FT_Int num_springs = 0;
AH_Spring* springs = 0;
/* first of all, count stem springs */
for ( stem = stems; stem+1 < stem_limit; stem++ )
{
AH_Stem* stem2;
for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
if (stem_spring_area(stem,stem2))
num_springs++;
}
/* then allocate and build the springs table */
if (num_springs > 0)
{
AH_Spring* spring;
/* allocate table of springs */
if ( ALLOC_ARRAY( springs, num_springs, AH_Spring ) )
goto Exit;
/* fill the springs table */
spring = springs;
for ( stem = stems; stem+1 < stem_limit; stem++ )
{
AH_Stem* stem2;
FT_Pos area;
for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
{
area = stem_spring_area(stem,stem2);
if (area)
{
/* add a new spring here */
spring->stem1 = stem;
spring->stem2 = stem2;
spring->owidth = stem2->opos - (stem->opos + stem->owidth);
spring->tension = 0;
spring++;
}
}
}
}
*p_num_springs = num_springs;
*p_springs = springs;
stems = optimizer->vert_stems;
stem_limit = stems + optimizer->num_vstems;
p_springs = &optimizer->vert_springs;
p_num_springs = &optimizer->num_vsprings;
}
Exit:
#ifdef DEBUG_OPTIM
AH_Dump_Springs(optimizer);
#endif
return error;
}
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** OPTIMISE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/
/**** ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
#ifndef BRUTE_FORCE
/* compute all spring tensions */
static
void optim_compute_tensions( AH_Optimizer* optimizer )
{
AH_Spring* spring = optimizer->springs;
AH_Spring* limit = spring + optimizer->num_springs;
for ( ; spring < limit; spring++ )
{
AH_Stem* stem1 = spring->stem1;
AH_Stem* stem2 = spring->stem2;
FT_Int status;
FT_Pos width;
FT_Pos tension;
FT_Pos sign;
/* compute the tension, it simply is -K*(new_width-old_width) */
width = stem2->pos - (stem1->pos + stem1->width);
tension = width - spring->owidth;
sign = 1;
if (tension < 0)
{
sign = -1;
tension = -tension;
}
if (width <= 0)
tension = 32000;
else
tension = (tension << 10)/width;
tension = -sign*FT_MulFix( tension, optimizer->tension_scale );
spring->tension = tension;
/* now, distribute tension among the englobing stems, if they */
/* are able to move.. */
status = 0;
if (stem1->pos <= stem1->min_pos)
status |= 1;
if (stem2->pos >= stem2->max_pos)
status |= 2;
if (!status)
tension /= 2;
if ((status & 1)== 0)
stem1->force -= tension;
if ((status & 2)== 0)
stem2->force += tension;
}
}
/* compute all stem movements - returns 0 if nothing moved */
static
int optim_compute_stem_movements( AH_Optimizer* optimizer )
{
AH_Stem* stems = optimizer->stems;
AH_Stem* limit = stems + optimizer->num_stems;
AH_Stem* stem = stems;
int moved = 0;
/* set initial forces to velocity */
for ( stem = stems; stem < limit; stem++ )
{
stem->force = stem->velocity;
stem->velocity /= 2; /* XXXX: Heuristics */
}
/* compute the sum of forces applied on each stem */
optim_compute_tensions( optimizer );
#ifdef DEBUG_OPTIM
AH_Dump_Springs( optimizer );
AH_Dump_Stems2( optimizer );
#endif
/* now, see if something can move ? */
for ( stem = stems; stem < limit; stem++ )
{
if (stem->force > optimizer->tension_threshold)
{
/* there is enough tension to move the stem to the right */
if (stem->pos < stem->max_pos)
{
stem->pos += 64;
stem->velocity = stem->force/2;
moved = 1;
}
else
stem->velocity = 0;
}
else if (stem->force < optimizer->tension_threshold)
{
/* there is enough tension to move the stem to the left */
if (stem->pos > stem->min_pos)
{
stem->pos -= 64;
stem->velocity = stem->force/2;
moved = 1;
}
else
stem->velocity = 0;
}
}
/* return 0 if nothing moved */
return moved;
}
#endif /* BRUTE_FORCE */
/* compute current global distortion from springs */
static
FT_Pos optim_compute_distorsion( AH_Optimizer* optimizer )
{
AH_Spring* spring = optimizer->springs;
AH_Spring* limit = spring + optimizer->num_springs;
FT_Pos distorsion = 0;
for ( ; spring < limit; spring++ )
{
AH_Stem* stem1 = spring->stem1;
AH_Stem* stem2 = spring->stem2;
FT_Pos width;
width = stem2->pos - (stem1->pos + stem1->width);
width -= spring->owidth;
if (width < 0)
width = -width;
distorsion += width;
}
return distorsion;
}
/* record stems configuration in "best of" history */
static
void optim_record_configuration( AH_Optimizer* optimizer )
{
FT_Pos distorsion;
AH_Configuration* configs = optimizer->configs;
AH_Configuration* limit = configs + optimizer->num_configs;
AH_Configuration* config;
distorsion = optim_compute_distorsion( optimizer );
LOG(( "config distorsion = %.1f ", FLOAT(distorsion*64) ));
/* check that we really need to add this configuration to our */
/* sorted history.. */
if ( limit > configs && limit[-1].distorsion < distorsion )
{
LOG(( "ejected\n" ));
return;
}
/* add new configuration at the end of the table */
{
int n;
config = limit;
if (optimizer->num_configs < AH_MAX_CONFIGS)
optimizer->num_configs++;
else
config--;
config->distorsion = distorsion;
for ( n = 0; n < optimizer->num_stems; n++ )
config->positions[n] = optimizer->stems[n].pos;
}
/* move the current configuration towards the front of the list */
/* when necessary, yes this is slow bubble sort ;-) */
while ( config > configs && config[0].distorsion < config[-1].distorsion )
{
AH_Configuration temp;
config--;
temp = config[0];
config[0] = config[1];
config[1] = temp;
}
LOG(( "recorded !!\n" ));
}
#ifdef BRUTE_FORCE
/* optimize outline in a single direction */
static
void optim_compute( AH_Optimizer* optimizer )
{
int n;
FT_Bool moved;
AH_Stem* stem = optimizer->stems;
AH_Stem* limit = stem + optimizer->num_stems;
/* empty, exit */
if (stem >= limit)
return;
optimizer->num_configs = 0;
stem = optimizer->stems;
for ( ; stem < limit; stem++ )
stem->pos = stem->min_pos;
do
{
/* record current configuration */
optim_record_configuration(optimizer);
/* now change configuration */
moved = 0;
for ( stem = optimizer->stems; stem < limit; stem++ )
{
if (stem->pos < stem->max_pos)
{
stem->pos += 64;
moved = 1;
break;
}
stem->pos = stem->min_pos;
}
}
while (moved);
/* now, set the best stem positions */
for ( n = 0; n < optimizer->num_stems; n++ )
{
AH_Stem* stem = optimizer->stems + n;
FT_Pos pos = optimizer->configs[0].positions[n];
stem->edge1->pos = pos;
stem->edge2->pos = pos + stem->width;
stem->edge1->flags |= ah_edge_done;
stem->edge2->flags |= ah_edge_done;
}
}
#else
/* optimize outline in a single direction */
static
void optim_compute( AH_Optimizer* optimizer )
{
int n, counter, counter2;
optimizer->num_configs = 0;
optimizer->tension_scale = 0x80000L;
optimizer->tension_threshold = 64;
/* record initial configuration threshold */
optim_record_configuration(optimizer);
counter = 0;
for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- )
{
if (counter == 0)
counter = 2*optimizer->num_stems;
if (!optim_compute_stem_movements( optimizer ))
break;
optim_record_configuration(optimizer);
counter--;
if (counter == 0)
optimizer->tension_scale /= 2;
}
/* now, set the best stem positions */
for ( n = 0; n < optimizer->num_stems; n++ )
{
AH_Stem* stem = optimizer->stems + n;
FT_Pos pos = optimizer->configs[0].positions[n];
stem->edge1->pos = pos;
stem->edge2->pos = pos + stem->width;
stem->edge1->flags |= ah_edge_done;
stem->edge2->flags |= ah_edge_done;
}
}
#endif
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/**** ****/
/**** HIGH-LEVEL OPTIMIZER API ****/
/**** ****/
/**** ****/
/**** ****/
/*************************************************************************/
/*************************************************************************/
/*************************************************************************/
/* releases the optimisation data */
void AH_Optimizer_Done( AH_Optimizer* optimizer )
{
if (optimizer)
{
FT_Memory memory = optimizer->memory;
FREE( optimizer->horz_stems );
FREE( optimizer->vert_stems );
FREE( optimizer->horz_springs );
FREE( optimizer->vert_springs );
FREE( optimizer->positions );
}
}
/* loads the outline into the optimizer */
int AH_Optimizer_Init( AH_Optimizer* optimizer,
AH_Outline* outline,
FT_Memory memory )
{
FT_Error error;
MEM_Set( optimizer, 0, sizeof(*optimizer));
optimizer->outline = outline;
optimizer->memory = memory;
LOG(( "initializing new optimizer\n" ));
/* compute stems and springs */
error = optim_compute_stems ( optimizer ) ||
optim_compute_springs( optimizer );
if (error) goto Fail;
/* allocate stem positions history and configurations */
{
int n, max_stems;
max_stems = optimizer->num_hstems;
if (max_stems < optimizer->num_vstems)
max_stems = optimizer->num_vstems;
if ( ALLOC_ARRAY( optimizer->positions, max_stems*AH_MAX_CONFIGS, FT_Pos ) )
goto Fail;
optimizer->num_configs = 0;
for ( n = 0; n < AH_MAX_CONFIGS; n++ )
optimizer->configs[n].positions = optimizer->positions + n*max_stems;
}
return error;
Fail:
AH_Optimizer_Done( optimizer );
return error;
}
/* compute optimal outline */
void AH_Optimizer_Compute( AH_Optimizer* optimizer )
{
optimizer->num_stems = optimizer->num_hstems;
optimizer->stems = optimizer->horz_stems;
optimizer->num_springs = optimizer->num_hsprings;
optimizer->springs = optimizer->horz_springs;
if (optimizer->num_springs > 0)
{
LOG(( "horizontal optimisation ------------------------\n" ));
optim_compute( optimizer );
}
optimizer->num_stems = optimizer->num_vstems;
optimizer->stems = optimizer->vert_stems;
optimizer->num_springs = optimizer->num_vsprings;
optimizer->springs = optimizer->vert_springs;
if (optimizer->num_springs)
{
LOG(( "vertical optimisation --------------------------\n" ));
optim_compute( optimizer );
}
}

137
src/autohint/ahoptim.h Normal file
View File

@ -0,0 +1,137 @@
/***************************************************************************/
/* */
/* FreeType Auto-Gridder Outline Optimisation */
/* */
/* 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. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGOPTIM_H
#define AGOPTIM_H
#ifdef FT_FLAT_COMPILE
#include "ahtypes.h"
#else
#include <autohint/ahtypes.h>
#endif
/* the maximal number of stem configurations to record during optimisation */
#define AH_MAX_CONFIGS 8
typedef struct AH_Stem_
{
FT_Pos pos; /* current position */
FT_Pos velocity; /* current velocity */
FT_Pos force; /* sum of current forces */
FT_Pos width; /* normalized width */
FT_Pos min_pos; /* minimum grid position */
FT_Pos max_pos; /* maximum grid position */
AH_Edge* edge1; /* left/bottom edge */
AH_Edge* edge2; /* right/top edge */
FT_Pos opos; /* original position */
FT_Pos owidth; /* original width */
FT_Pos min_coord; /* minimum coordinate */
FT_Pos max_coord; /* maximum coordinate */
} AH_Stem;
/* A spring between two stems */
typedef struct AH_Spring_
{
AH_Stem* stem1;
AH_Stem* stem2;
FT_Pos owidth; /* original width */
FT_Pos tension; /* current tension */
} AH_Spring;
/* A configuration records the position of each stem at a given time */
/* as well as the associated distortion.. */
typedef struct AH_Configuration_
{
FT_Pos* positions;
FT_Long distorsion;
} AH_Configuration;
typedef struct AH_Optimizer_
{
FT_Memory memory;
AH_Outline* outline;
FT_Int num_hstems;
AH_Stem* horz_stems;
FT_Int num_vstems;
AH_Stem* vert_stems;
FT_Int num_hsprings;
FT_Int num_vsprings;
AH_Spring* horz_springs;
AH_Spring* vert_springs;
FT_Int num_configs;
AH_Configuration configs[ AH_MAX_CONFIGS ];
FT_Pos* positions;
/* during each pass, use these instead */
FT_Int num_stems;
AH_Stem* stems;
FT_Int num_springs;
AH_Spring* springs;
FT_Bool vertical;
FT_Fixed tension_scale;
FT_Pos tension_threshold;
} AH_Optimizer;
/* loads the outline into the optimizer */
extern
int AH_Optimizer_Init( AH_Optimizer* optimizer,
AH_Outline* outline,
FT_Memory memory );
/* compute optimal outline */
extern
void AH_Optimizer_Compute( AH_Optimizer* optimizer );
/* releases the optimisation data */
extern
void AH_Optimizer_Done( AH_Optimizer* optimizer );
#endif /* AGOPTIM_H */

440
src/autohint/ahtypes.h Normal file
View File

@ -0,0 +1,440 @@
/***************************************************************************/
/* */
/* ahtypes.h */
/* */
/* General types and definitions for the auto-hint module */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#ifndef AGTYPES_H
#define AGTYPES_H
#include <freetype/internal/ftobjs.h> /* for freetype.h + LOCAL_DEF etc.. */
#ifdef FT_FLAT_COMPILE
#include "ahloader.h" /* glyph loader types & declarations */
#else
#include <autohint/ahloader.h> /* glyph loader types & declarations */
#endif
#define xxDEBUG_AG
#ifdef DEBUG_AG
#include <stdio.h>
#define AH_LOG(x) printf##x
#else
#define AH_LOG(x) /* nothing */
#endif
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/**** ****/
/**** COMPILE-TIME BUILD OPTIONS ****/
/**** ****/
/**** Toggle these configuration macros to experiment with ****/
/**** "features" 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 */
#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 AH_MAX_WIDTHS 12
#define AH_MAX_HEIGHTS 12
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/**** ****/
/**** TYPES DEFINITIONS ****/
/**** ****/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/* see agangles.h */
typedef FT_Int AH_Angle;
/* hint flags */
typedef enum AH_Flags_
{
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 */
typedef enum AH_Edge_Flags_
{
ah_edge_normal = 0,
ah_edge_round = 1,
ah_edge_serif = 2,
ah_edge_done = 4
} AH_Edge_Flags;
/* hint directions - the values are computed so that two vectors are */
/* in opposite directions iff "dir1+dir2 == 0" */
typedef enum AH_Direction_
{
ah_dir_none = 4,
ah_dir_right = 1,
ah_dir_left = -1,
ah_dir_up = 2,
ah_dir_down = -2
} AH_Direction;
typedef struct AH_Point AH_Point;
typedef struct AH_Segment AH_Segment;
typedef struct AH_Edge AH_Edge;
/***************************************************************************
*
* <Struct>
* AH_Point
*
* <Description>
* A structure used to model an outline point to the AH_Outline type
*
* <Fields>
* flags :: current point hint flags
* ox, oy :: current original scaled coordinates
* fx, fy :: current coordinates in font units
* x, y :: current hinter coordinates
* u, v :: point coordinates - meaning varies with context
*
* in_dir :: direction of inwards vector (prev->point)
* out_dir :: direction of outwards vector (point->next)
*
* in_angle :: angle of inwards vector
* out_angle :: angle of outwards vector
*
* next :: next point in same contour
* prev :: previous point in same contour
*
*/
struct AH_Point
{
AH_Flags flags; /* point flags used by hinter */
FT_Pos ox, oy;
FT_Pos fx, fy;
FT_Pos x, y;
FT_Pos u, v;
AH_Direction in_dir; /* direction of inwards vector */
AH_Direction out_dir; /* direction of outwards vector */
AH_Angle in_angle;
AH_Angle out_angle;
AH_Point* next; /* next point in contour */
AH_Point* prev; /* previous point in contour */
};
/***************************************************************************
*
* <Struct>
* AH_Segment
*
* <Description>
* a structure used to describe an edge segment to the auto-hinter. A
* segment is simply a sequence of successive points located on the same
* horizontal or vertical "position", in a given direction.
*
* <Fields>
* flags :: segment edge flags ( straight, rounded.. )
* dir :: segment direction
*
* first :: first point in segment
* last :: last point in segment
* contour :: ptr to first point of segment's contour
*
* pos :: segment position in font units
* size :: segment size
*
* edge :: edge of current segment
* edge_next :: next segment on 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
{
AH_Edge_Flags flags;
AH_Direction dir;
AH_Point* first; /* first point in edge segment */
AH_Point* last; /* last point in edge segment */
AH_Point** contour; /* ptr to first point of segment's contour */
FT_Pos pos; /* position of segment */
FT_Pos min_coord; /* minimum coordinate of segment */
FT_Pos max_coord; /* maximum coordinate of segment */
AH_Edge* edge;
AH_Segment* edge_next;
AH_Segment* link; /* link segment */
AH_Segment* serif; /* primary segment for serifs */
FT_Pos num_linked; /* number of linked segments */
FT_Int score;
};
/***************************************************************************
*
* <Struct>
* AH_Edge
*
* <Description>
* a structure used to describe an edge, which really is a horizontal
* or vertical coordinate which will be hinted depending on the segments
* located on it..
*
* <Fields>
* flags :: segment edge flags ( straight, rounded.. )
* dir :: main segment direction on this edge
*
* first :: first edge segment
* last :: last edge segment
*
* fpos :: original edge position in font units
* opos :: original scaled edge position
* pos :: hinted edge position
*
* link :: the linked edge
* serif :: the serif edge
* 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
{
AH_Edge_Flags flags;
AH_Direction dir;
AH_Segment* first;
AH_Segment* last;
FT_Pos fpos;
FT_Pos opos;
FT_Pos pos;
AH_Edge* link;
AH_Edge* serif;
FT_Int num_linked;
FT_Int score;
FT_Pos* blue_edge;
};
/* an outline as seen by the hinter */
typedef struct AH_Outline_
{
FT_Memory memory;
AH_Direction vert_major_dir; /* vertical major direction */
AH_Direction horz_major_dir; /* horizontal major direction */
FT_Fixed x_scale;
FT_Fixed y_scale;
FT_Pos edge_distance_threshold;
FT_Int max_points;
FT_Int num_points;
AH_Point* points;
FT_Int max_contours;
FT_Int num_contours;
AH_Point** contours;
FT_Int num_hedges;
AH_Edge* horz_edges;
FT_Int num_vedges;
AH_Edge* vert_edges;
FT_Int num_hsegments;
AH_Segment* horz_segments;
FT_Int num_vsegments;
AH_Segment* vert_segments;
} AH_Outline;
typedef enum 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;
/************************************************************************
*
* <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 struct AH_Globals_
{
FT_Int num_widths;
FT_Int num_heights;
FT_Pos widths [ AH_MAX_WIDTHS ];
FT_Pos heights[ AH_MAX_HEIGHTS ];
FT_Pos blue_refs [ ah_blue_max ];
FT_Pos blue_shoots[ ah_blue_max ];
} AH_Globals;
/************************************************************************
*
* <Struct>
* AH_Face_Globals
*
* <Description>
* Holds the complete global metrics for a given font face (i.e. the
* design units version + a scaled version + the current scales used)
*
* <Fields>
* face :: handle to source face object
* design :: globals in font design units
* scaled :: scaled globals in sub-pixel values
* x_scale :: current horizontal scale
* y_scale :: current vertical scale
*
************************************************************************/
typedef struct AH_Face_Globals_
{
FT_Face face;
AH_Globals design;
AH_Globals scaled;
FT_Fixed x_scale;
FT_Fixed y_scale;
FT_Bool control_overshoot;
} AH_Face_Globals;
typedef struct AH_Hinter
{
FT_Memory memory;
FT_Long flags;
FT_Int algorithm;
FT_Face face;
AH_Face_Globals* globals;
AH_Outline* glyph;
AH_Loader* loader;
FT_Vector pp1;
FT_Vector pp2;
} AH_Hinter;
#endif /* AGTYPES_H */

40
src/autohint/autohint.c Normal file
View File

@ -0,0 +1,40 @@
/***************************************************************************/
/* */
/* autohint.c */
/* */
/* Automatic Hinting wrapper. */
/* */
/* Copyright 2000: Catharon Productions Inc. */
/* Author: David Turner */
/* */
/* This file is part of the Catharon Typography Project and shall only */
/* 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 */
/* */
/***************************************************************************/
#define FT_MAKE_OPTION_SINGLE_OBJECT
#ifdef FT_FLAT_COMPILE
#include "ahangles.c"
#include "ahglyph.c"
#include "ahglobal.c"
#include "ahhint.c"
#include "ahmodule.c"
#else
#include <autohint/ahangles.c>
#include <autohint/ahglyph.c>
#include <autohint/ahglobal.c>
#include <autohint/ahhint.c>
#include <autohint/ahmodule.c>
#endif

54
src/autohint/mather.py Normal file
View File

@ -0,0 +1,54 @@
import math
ag_pi = 256
def print_arctan( atan_bits ):
atan_base = 1 << atan_bits
print "static AH_Angle ag_arctan[ 1L << AG_ATAN_BITS ] ="
print "{"
count = 0
line = ""
for n in range(atan_base):
comma = ","
if (n == atan_base-1):
comma = ""
angle = math.atan(n*1.0/atan_base)/math.pi*ag_pi
line = line + " " + repr(int(angle+0.5)) + comma
count = count+1;
if (count == 8):
count = 0
print line
line = ""
if (count >0):
print line
print "};"
def print_sines():
print "static FT_Fixed ah_sines[ AG_HALF_PI+1 ] ="
print "{"
count = 0
line = ""
for n in range(ag_pi/2):
sinus = math.sin(n*math.pi/ag_pi)
line = line + " " + repr(int(65536.0*sinus)) + ","
count = count+1
if (count == 8):
count = 0
print line
line = ""
if (count > 0):
print line
print " 65536"
print "};"
print_arctan(8)
print

7
src/autohint/module.mk Normal file
View File

@ -0,0 +1,7 @@
make_module_list: add_autohint_module
add_autohint_module:
$(OPEN_DRIVER)autohint_module_class$(CLOSE_DRIVER)
$(ECHO_DRIVER)autohint $(ECHO_DRIVER_DESC)automatic hinting module$(ECHO_DRIVER_DONE)
# EOF

86
src/autohint/rules.mk Normal file
View File

@ -0,0 +1,86 @@
#
# FreeType 2 auto-hinter module configuration rules
#
#
# Copyright 2000: Catharon Productions Inc.
# Author: David Turner
#
# This file is part of the Catharon Typography Project and shall only
# 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_DIR := $(SRC_)autohint
AUTO_DIR_ := $(AUTO_DIR)$(SEP)
# compilation flags for the driver
#
AUTO_COMPILE := $(FT_COMPILE)
# AUTO driver sources (i.e., C files)
#
AUTO_DRV_SRC := $(AUTO_DIR_)ahangles.c \
$(AUTO_DIR_)ahglobal.c \
$(AUTO_DIR_)ahglyph.c \
$(AUTO_DIR_)ahhint.c \
$(AUTO_DIR_)ahmodule.c
# AUTO driver headers
#
AUTO_DRV_H := $(AUTO_DRV_SRC:%c=%h)
# AUTO driver object(s)
#
# AUTO_DRV_OBJ_M is used during `multi' builds.
# AUTO_DRV_OBJ_S is used during `single' builds.
#
AUTO_DRV_OBJ_M := $(AUTO_DRV_SRC:$(AUTO_DIR_)%.c=$(OBJ_)%.$O)
AUTO_DRV_OBJ_S := $(OBJ_)autohint.$O
# AUTO driver source file for single build
#
AUTO_DRV_SRC_S := $(AUTO_DIR_)autohint.c
# AUTO driver - single object
#
$(AUTO_DRV_OBJ_S): $(AUTO_DRV_SRC_S) $(AUTO_DRV_SRC) \
$(FREETYPE_H) $(AUTO_DRV_H)
$(AUTO_COMPILE) $T$@ $(AUTO_DRV_SRC_S)
# AUTO driver - multiple objects
#
$(OBJ_)%.$O: $(AUTO_DIR_)%.c $(FREETYPE_H) $(AUTO_DRV_H)
$(AUTO_COMPILE) $T$@ $<
# update main driver object lists
#
DRV_OBJS_S += $(AUTO_DRV_OBJ_S)
DRV_OBJS_M += $(AUTO_DRV_OBJ_M)
# EOF