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:
parent
6930b45f78
commit
3469d0d038
|
@ -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 ---
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||||
|
};
|
|
@ -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 */
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue