ref: ff9d2415a7a192520ea198187dbdb6408625e210
parent: 03f06f0f08f1ad864261a5e5644862ef654506d4
author: David Turner <[email protected]>
date: Sun Nov 23 16:39:51 EST 2003
* src/autofit/*: more updates
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2003-11-22 David Turner <[email protected]>
+
+ * src/autofit/*: more updates
+
2003-11-13 John A. Boyd Jr. <[email protected]>
* src/bdf/bdfdrivr.c (bdf_interpret_style), src/pcf/pcfread.c
--- a/README
+++ b/README
@@ -9,7 +9,7 @@
is called `libttf'. They are *not* compatible!
- FreeType 2.1.7
+ FreeType 2.1.8
==============
Please read the docs/CHANGES file, it contains IMPORTANT INFORMATION.
@@ -19,9 +19,9 @@
Note that the FreeType 2 documentation is now available as a
separate package from our sites. See:
- ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.7.tar.bz2
- ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.7.tar.gz
- ftp://ftp.freetype.org/pub/freetype2/ftdoc216.zip
+ ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.8.tar.bz2
+ ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.1.8.tar.gz
+ ftp://ftp.freetype.org/pub/freetype2/ftdoc218.zip
Bugs
--- a/builds/unix/configure.ac
+++ b/builds/unix/configure.ac
@@ -8,7 +8,7 @@
# Don't forget to update docs/VERSION.DLL!
-version_info='9:5:3'
+version_info='9:6:3'
AC_SUBST([version_info])
ft_version=`echo $version_info | tr : .`
AC_SUBST([ft_version])
--- a/docs/VERSION.DLL
+++ b/docs/VERSION.DLL
@@ -52,6 +52,7 @@
release libtool so
-------------------------------
+ 2.1.8 9.6.3 6.3.6
2.1.7 9.5.3 6.3.5
2.1.6 9.5.3 6.3.5
2.1.5 9.4.3 6.3.4
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -44,7 +44,7 @@
/* */
#define FREETYPE_MAJOR 2
#define FREETYPE_MINOR 1
-#define FREETYPE_PATCH 7
+#define FREETYPE_PATCH 8
#include <ft2build.h>
--- a/src/autofit/afangles.c
+++ b/src/autofit/afangles.c
@@ -9,6 +9,7 @@
90, 64, 38, 20, 10, 5, 3, 1, 1
};
+
static FT_Int
af_angle_prenorm( FT_Vector* vec )
{
@@ -162,3 +163,29 @@
return delta;
}
+
+ /* well, this needs to be somewhere, right :-)
+ */
+
+ FT_LOCAL_DEF( void )
+ af_sort_pos( FT_UInt count,
+ FT_Pos* table )
+ {
+ FT_Int i, j;
+ FT_Pos swap;
+
+
+ for ( i = 1; i < count; i++ )
+ {
+ for ( j = i; j > 0; j-- )
+ {
+ if ( table[j] > table[j - 1] )
+ break;
+
+ swap = table[j];
+ table[j] = table[j - 1];
+ table[j - 1] = swap;
+ }
+ }
+ }
+
\ No newline at end of file
--- /dev/null
+++ b/src/autofit/afglobal.c
@@ -1,0 +1,231 @@
+#include "afglobal.h"
+#include "aflatin.h"
+
+ /* populate this list when you add new scripts
+ */
+ static AF_ScriptClass const af_script_class_list[] =
+ {
+ & af_latin_script_class,
+
+ NULL /* do not remove */
+ };
+
+#define AF_SCRIPT_LIST_DEFAULT 0 /* index of default script in 'af_script_class_list' */
+#define AF_SCRIPT_LIST_NONE 255 /* indicates an uncovered glyph */
+
+ /*
+ * note that glyph_scripts[] is used to map each glyph into
+ * an index into the 'af_script_class_list' array.
+ *
+ */
+ typedef struct AF_FaceGlobalsRec_
+ {
+ FT_Face face;
+ FT_UInt glyph_count; /* same as face->num_glyphs */
+ FT_Byte* glyph_scripts;
+
+ AF_ScriptMetrics metrics[ AF_SCRIPT_MAX ];
+
+ } AF_FaceGlobalsRec, *AF_FaceGlobals;
+
+
+
+
+ /* this function is used to compute the script index of each glyph
+ * within a given face
+ */
+ static FT_Error
+ af_face_globals_compute_script_coverage( AF_FaceGlobals globals )
+ {
+ FT_Error error = 0;
+ FT_Face face = globals->face;
+ FT_CharMap old_charmap = face->charmap;
+ FT_Byte* gscripts = globals->glyph_scripts;
+ FT_UInt ss;
+
+ /* the value 255 means "uncovered glyph"
+ */
+ FT_MEM_SET( globals->glyph_scripts,
+ AF_SCRIPT_LIST_NONE,
+ globals->glyph_count );
+
+ error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+ if ( error )
+ {
+ /* ignore this error, we'll simply use Latin as the standard
+ * script. XXX: Shouldn't we rather disable hinting ??
+ */
+ error = 0;
+ goto Exit;
+ }
+
+ /* scan each script in a Unicode charmap
+ */
+ for ( ss = 0; af_script_classes[ss]; ss++ )
+ {
+ AF_ScriptClass clazz = af_script_classes[ss];
+ AF_Script_UniRange range;
+
+ /* scan all unicode points in the range, and set the corresponding
+ * glyph script index
+ */
+ for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
+ {
+ FT_ULong charcode = range->first;
+ FT_UInt gindex;
+
+ gindex = FT_Get_Char_Index( face, charcode );
+
+ if ( gindex != 0 &&
+ gindex < globals->glyph_count &&
+ gscripts[ gindex ] == AF_SCRIPT_LIST_NONE )
+ {
+ gscripts[ gindex ] = (FT_Byte) ss;
+ }
+ for (;;)
+ {
+ charcode = FT_Get_Next_Char( face, charcode, &gindex );
+
+ if ( gindex == 0 || charcode > range->last )
+ break;
+
+ if ( gindex < globals->glyph_count &&
+ gscripts[ gindex ] == AF_SCRIPT_LIST_NONE )
+ {
+ gscripts[ gindex ] = (FT_Byte) ss;
+ }
+ }
+ }
+ }
+
+ Exit:
+ /* by default, all uncovered glyphs are set to the latin script
+ * XXX: shouldnt' we disable hinting or do something similar ?
+ */
+ {
+ FT_UInt nn;
+
+ for ( nn = 0; nn < globals->glyph_count; nn++ )
+ {
+ if ( gscripts[ nn ] == AF_SCRIPT_LIST_NONE )
+ gscripts[ nn ] = AF_SCRIPT_LIST_DEFAULT;
+ }
+ }
+
+ FT_Set_Charmap( face, old_charmap );
+ return error;
+ }
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_face_globals_new( FT_Face face,
+ AF_FaceGlobals *aglobals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ AF_FaceGlobals globals;
+
+ memory = face->memory;
+
+ if ( !FT_ALLOC( globals, sizeof(*globals) +
+ face->num_glyphs*sizeof(FT_Byte) ) )
+ {
+ globals->face = face;
+ globals->glyph_count = face->num_glyphs;
+ globals->glyph_scripts = (FT_Byte*)( globals+1 );
+
+ error = af_face_globals_compute_script_coverage( globals );
+ if ( error )
+ {
+ af_face_globals_free( globals );
+ globals = NULL;
+ }
+ }
+
+ Exit:
+ *aglobals = globals;
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_face_globals_free( AF_FaceGlobals globals )
+ {
+ if ( globals )
+ {
+ FT_Memory memory = globals->face->memory;
+ FT_UInt nn;
+
+ for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
+ {
+ if ( globals->metrics[nn] )
+ {
+ AF_ScriptClass clazz = af_script_classes[nn];
+
+ FT_ASSERT( globals->metrics[nn].clazz == clazz );
+
+ if ( clazz->script_metrics_done )
+ clazz->script_metrics_done( globals->metrics[nn] );
+
+ FT_FREE( globals->metrics[nn] );
+ }
+ }
+
+ globals->glyph_count = NULL;
+ globals->glyph_scripts = NULL; /* no need to free this one !! */
+ globals->face = NULL;
+ FT_FREE( globals );
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_face_globals_get_metrics( AF_FaceGlobals globals,
+ FT_UInt gindex,
+ AF_ScriptMetrics *ametrics )
+ {
+ FT_Script script;
+ AF_ScriptMetrics metrics = NULL;
+ FT_UInt index;
+ AF_ScriptClass clazz;
+ FT_Error error;
+
+ if ( gindex >= globals->glyph_count )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ index = globals->glyph_scripts[ gindex ];
+ clazz = af_script_class_list[ index ];
+ metrics = globals->metrics[ clazz->script ];
+ if ( metrics == NULL )
+ {
+ /* create the global metrics object when needed
+ */
+ if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
+ goto Exit;
+
+ metrics->clazz = clazz;
+
+ if ( clazz->script_metrics_init )
+ {
+ error = clazz->script_metrics_init( metrics, face );
+ if ( error )
+ {
+ if ( clazz->script_metrics_done )
+ clazz->script_metrics_done( metrics );
+
+ FT_FREE( metrics );
+ goto Exit;
+ }
+ }
+
+ globals->metrics[ script ] = metrics;
+ }
+
+ Exit:
+ *ametrics = metrics;
+ return error;
+ }
--- /dev/null
+++ b/src/autofit/afglobal.h
@@ -1,0 +1,42 @@
+#ifndef __AF_GLOBAL_H__
+#define __AF_GLOBAL_H__
+
+#include "aftypes.h"
+
+FT_BEGIN_HEADER
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
+ /***** F A C E G L O B A L S *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+
+ /*
+ * models the global hints data for a given face, decomposed into
+ * script-specific items..
+ *
+ */
+ typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals;
+
+
+ FT_LOCAL( FT_Error )
+ af_face_globals_new( FT_Face face,
+ AF_FaceGlobals *aglobals );
+
+
+ FT_LOCAL( FT_Error )
+ af_face_globals_get_metrics( AF_FaceGlobals globals,
+ FT_UInt gindex,
+ AF_ScriptMetrics *ametrics );
+
+ FT_LOCAL( void )
+ af_face_globals_free( AF_FaceGlobals globals );
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __AF_GLOBALS_H__ */
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -5,7 +5,7 @@
#include <stdio.h>
void
- af_outline_hints_dump_edges( AF_OutlineHints hints )
+ af_glyph_hints_dump_edges( AF_GlyphHints hints )
{
AF_Edge edges;
AF_Edge edge_limit;
@@ -57,7 +57,7 @@
/* A function used to dump the array of linked segments */
void
- af_outline_hints_dump_segments( AF_OutlineHints hints )
+ af_glyph_hints_dump_segments( AF_GlyphHints hints )
{
AF_Segment segments;
AF_Segment segment_limit;
@@ -139,15 +139,12 @@
/* compute all inflex points in a given glyph */
static void
- af_outline_hints_compute_inflections( AF_OutlineHints hints )
+ af_glyph_hints_compute_inflections( AF_GlyphHints hints )
{
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
- /* load original coordinates in (u,v) */
- af_outline_hints_setup_uv( hints, outline, AF_UV_FXY );
-
/* do each contour separately */
for ( ; contour < contour_limit; contour++ )
{
@@ -172,10 +169,10 @@
if ( end == first )
goto Skip;
- } while ( end->u == first->u && end->v == first->v );
+ } while ( end->fx == first->fx && end->fy == first->fy );
- angle_seg = af_angle( end->u - start->u,
- end->v - start->v );
+ angle_seg = af_angle( end->fx - start->fx,
+ end->fy - start->fy );
/* extend the segment start whenever possible */
before = start;
@@ -188,10 +185,10 @@
if ( before == first )
goto Skip;
- } while ( before->u == start->u && before->v == start->v );
+ } while ( before->fx == start->fx && before->fy == start->fy );
- angle_in = af_angle( start->u - before->u,
- start->v - before->v );
+ angle_in = af_angle( start->fx - before->fx,
+ start->fy - before->fy );
} while ( angle_in == angle_seg );
@@ -212,12 +209,12 @@
if ( after == first )
finished = 1;
- } while ( end->u == after->u && end->v == after->v );
+ } while ( end->fx == after->fx && end->fy == after->fy );
- vec.x = after->u - end->u;
- vec.y = after->v - end->v;
- angle_out = af_angle( after->u - end->u,
- after->v - end->v );
+ vec.x = after->fx - end->fx;
+ vec.y = after->fy - end->fy;
+ angle_out = af_angle( after->fx - end->fx,
+ after->fy - end->fy );
} while ( angle_out == angle_seg );
@@ -252,17 +249,17 @@
FT_LOCAL_DEF( void )
- af_outline_hints_init( AF_OutlineHints hints,
- FT_Memory memory )
+ af_glyph_hints_init( AF_GlyphHints hints,
+ FT_Memory memory )
{
FT_ZERO( hints );
hints->memory = memory;
- }
+ }
FT_LOCAL_DEF( void )
- af_outline_hints_done( AF_OutlineHints hints )
+ af_glyph_hints_done( AF_GlyphHints hints )
{
if ( hints && hints->memory )
{
@@ -275,7 +272,7 @@
for ( dim = 0; dim < 2; dim++ )
{
AF_AxisHints axis = &hints->axis[ dim ];
-
+
axis->num_segments = 0;
axis->num_edges = 0;
axis->segments = NULL;
@@ -285,11 +282,11 @@
FT_FREE( hints->contours );
hints->max_contours = 0;
hints->num_contours = 0;
-
+
FT_FREE( hints->points );
hints->num_points = 0;
hints->max_points = 0;
-
+
hints->memory = NULL;
}
}
@@ -297,23 +294,25 @@
FT_LOCAL_DEF( FT_Error )
- af_outline_hints_reset( AF_OutlineHints hints,
- FT_Outline* outline,
- FT_Fixed x_scale,
- FT_Fixed y_scale )
+ af_glyph_hints_reset( AF_GlyphHints hints,
+ FT_Outline* outline,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale,
+ FT_Pos x_delta,
+ FT_Pos y_delta )
{
FT_Error error = AF_Err_Ok;
-
+
FT_UInt old_max, new_max;
hints->num_points = 0;
hints->num_contours = 0;
-
+
hints->axis[0].num_segments = 0;
hints->axis[0].num_edges = 0;
hints->axis[1].num_segments = 0;
hints->axis[1].num_edges = 0;
-
+
/* first of all, reallocate the contours array when necessary
*/
new_max = (FT_UInt) outline->n_contours;
@@ -321,17 +320,17 @@
if ( new_max > old_max )
{
new_max = (new_max + 3) & ~3;
-
+
if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
goto Exit;
-
+
hints->max_contours = new_max;
}
- /* then, reallocate the points, segments & edges arrays if needed --
- * note that we reserved two additional point positions, used to
- * hint metrics appropriately
- */
+ /* then, reallocate the points, segments & edges arrays if needed --
+ * note that we reserved two additional point positions, used to
+ * hint metrics appropriately
+ */
new_max = (FT_UInt)( outline->n_points + 2 );
old_max = hints->max_points;
if ( new_max > old_max )
@@ -338,17 +337,17 @@
{
FT_Byte* items;
FT_ULong off1, off2, off3;
-
+
/* we store in a single buffer the following arrays:
*
* - an array of N AF_PointRec items
* - an array of 2*N AF_SegmentRec items
- * - an array of 2*N AF_EdgeRec items
+ * - an array of 2*N AF_EdgeRec items
*
*/
-
+
new_max = ( new_max + 2 + 7 ) & ~7;
-
+
#undef OFF_INCREMENT
#define OFF_INCREMENT( _off, _type, _count ) \
((((_off) + sizeof(_type)) & ~(sizeof(_type)) + ((_count)*sizeof(_type)))
@@ -368,15 +367,15 @@
hints->axis[1].edges = NULL;
goto Exit;
}
-
+
/* readjust some pointers
*/
hints->max_points = new_max;
hints->points = (AF_Point) items;
-
+
hints->axis[0].segments = (AF_Segment)( items + off1 );
hints->axis[1].segments = hints->axis[0].segments + new_max;
-
+
hints->axis[0].edges = (AF_Edge) ( items + off2 );
hints->axis[1].edges = hints->axis[0].edges + new_max;
}
@@ -422,8 +421,8 @@
{
point->fx = vec->x;
point->fy = vec->y;
- point->ox = point->x = FT_MulFix( vec->x, x_scale );
- point->oy = point->y = FT_MulFix( vec->y, y_scale );
+ point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
+ point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
switch ( FT_CURVE_TAG( *tag ) )
{
@@ -503,7 +502,7 @@
prev = point->prev;
in_x = point->fx - prev->fx;
in_y = point->fy - prev->fy;
-
+
point->in_dir = af_compute_direction( in_x, in_y );
next = point->next;
@@ -539,8 +538,8 @@
}
/* compute inflection points
- */
- af_outline_hints_compute_inflections( hints );
+ */
+ af_glyph_hints_compute_inflections( hints );
Exit:
return error;
@@ -547,80 +546,392 @@
}
+
+
+ /*
+ *
+ * E D G E P O I N T G R I D - F I T T I N G
+ *
+ */
+
+
FT_LOCAL_DEF( void )
- af_outline_hints_setup_uv( AF_OutlineHints hints,
- AF_UV source )
+ af_glyph_hints_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim )
{
- AF_Point point = hints->points;
- AF_Point point_limit = point + hints->num_points;
+ AF_AxisHints axis = & hints->axis[ dim ];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
-
- switch ( source )
+ for ( edge = edges; edge < edge_limit; edge++ )
{
- case AF_UV_FXY:
- for ( ; point < point_limit; point++ )
+ /* move the points of each segment */
+ /* in each edge to the edge's position */
+ AF_Segment seg = edge->first;
+
+
+ do
{
- point->u = point->fx;
- point->v = point->fy;
- }
- break;
+ AF_Point point = seg->first;
- case AF_UV_FYX:
- for ( ; point < point_limit; point++ )
+
+ for (;;)
+ {
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ point->x = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_X;
+ }
+ else
+ {
+ point->y = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_Y;
+ }
+
+ if ( point == seg->last )
+ break;
+
+ point = point->next;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+ }
+
+
+ /*
+ *
+ * S T R O N G P O I N T I N T E R P O L A T I O N
+ *
+ */
+
+
+ /* hint the strong points -- this is equivalent to the TrueType `IP' */
+ /* hinting instruction */
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_strong_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;;
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Flags touch_flag;
+ AF_Point point;
+ AF_Edge edge;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ touch_flag = AF_FLAG_TOUCH_X;
+ else
+ touch_flag = AF_FLAG_TOUCH_Y;
+
+ if ( edges < edge_limit )
+ {
+ AF_Point point;
+ AF_Edge edge;
+
+ for ( point = points; point < point_limit; point++ )
{
- point->u = point->fy;
- point->v = point->fx;
+ FT_Pos u, ou, fu; /* point position */
+ FT_Pos delta;
+
+
+ if ( point->flags & touch_flag )
+ continue;
+
+ /* if this point is candidate to weak interpolation, we will */
+ /* interpolate it after all strong points have been processed */
+ if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
+ !( point->flags & AF_FLAG_INFLECTION ) )
+ continue;
+
+ if ( dimension )
+ {
+ u = point->fy;
+ ou = point->oy;
+ }
+ else
+ {
+ u = point->fx;
+ ou = point->ox;
+ }
+
+ fu = u;
+
+ /* is the point before the first edge? */
+ edge = edges;
+ delta = edge->fpos - u;
+ if ( delta >= 0 )
+ {
+ u = edge->pos - ( edge->opos - ou );
+ goto Store_Point;
+ }
+
+ /* is the point after the last edge? */
+ edge = edge_limit - 1;
+ delta = u - edge->fpos;
+ if ( delta >= 0 )
+ {
+ u = edge->pos + ( ou - edge->opos );
+ goto Store_Point;
+ }
+
+ {
+ FT_UInt min, max, mid;
+ FT_Pos fpos;
+
+
+ /* find enclosing edges */
+ min = 0;
+ max = edge_limit - edges;
+
+ while ( min < max )
+ {
+ mid = ( max + min ) >> 1;
+ edge = edges + mid;
+ fpos = edge->fpos;
+
+ if ( u < fpos )
+ max = mid;
+ else if ( u > fpos )
+ min = mid + 1;
+ else
+ {
+ /* we are on the edge */
+ u = edge->pos;
+ goto Store_Point;
+ }
+ }
+
+ {
+ AF_Edge before = edges + min - 1;
+ AF_Edge after = edges + min + 0;
+
+
+ /* assert( before && after && before != after ) */
+ if ( before->scale == 0 )
+ before->scale = FT_DivFix( after->pos - before->pos,
+ after->fpos - before->fpos );
+
+ u = before->pos + FT_MulFix( fu - before->fpos,
+ before->scale );
+ }
+ }
+
+
+ Store_Point:
+
+ /* save the point position */
+ if ( dim == AF_DIMENSION_HORZ )
+ point->x = u;
+ else
+ point->y = u;
+
+ point->flags |= touch_flag;
}
- break;
+ }
+ }
- case AF_UV_OXY:
- for ( ; point < point_limit; point++ )
+
+ /*
+ *
+ * W E A K P O I N T I N T E R P O L A T I O N
+ *
+ */
+
+ static void
+ af_iup_shift( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref )
+ {
+ AF_Point p;
+ FT_Pos delta = ref->u - ref->v;
+
+
+ for ( p = p1; p < ref; p++ )
+ p->u = p->v + delta;
+
+ for ( p = ref + 1; p <= p2; p++ )
+ p->u = p->v + delta;
+ }
+
+
+ static void
+ af_iup_interp( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref1,
+ AF_Point ref2 )
+ {
+ AF_Point p;
+ FT_Pos u;
+ FT_Pos v1 = ref1->v;
+ FT_Pos v2 = ref2->v;
+ FT_Pos d1 = ref1->u - v1;
+ FT_Pos d2 = ref2->u - v2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ if ( v1 == v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
{
- point->u = point->ox;
- point->v = point->oy;
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else
+ u += d2;
+
+ p->u = u;
}
- break;
+ return;
+ }
- case AF_UV_OYX:
- for ( ; point < point_limit; point++ )
+ if ( v1 < v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
{
- point->u = point->oy;
- point->v = point->ox;
- }
- break;
+ u = p->v;
- case AF_UV_YX:
- for ( ; point < point_limit; point++ )
+ if ( u <= v1 )
+ u += d1;
+ else if ( u >= v2 )
+ u += d2;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ else
+ {
+ for ( p = p1; p <= p2; p++ )
{
- point->u = point->y;
- point->v = point->x;
+ u = p->v;
+
+ if ( u <= v2 )
+ u += d2;
+ else if ( u >= v1 )
+ u += d1;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
}
- break;
+ }
+ }
- case AF_UV_OX:
- for ( ; point < point_limit; point++ )
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_weak_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Flags touch_flag;
+ AF_Point point;
+ AF_Point end_point;
+ AF_Point first_point;
+
+
+ /* PASS 1: Move segment points to edge positions */
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ touch_flag = AF_FLAG_TOUCH_X;
+
+ for ( point = points; point < point_limit; point++ )
{
point->u = point->x;
point->v = point->ox;
}
- break;
+ }
+ else
+ {
+ touch_flag = AF_FLAG_TOUCH_Y;
- case AF_UV_OY:
- for ( ; point < point_limit; point++ )
+ for ( point = points; point < point_limit; points++ )
{
point->u = point->y;
point->v = point->oy;
}
- break;
+ }
- default:
- for ( ; point < point_limit; point++ )
+ point = points;
+
+ for ( ; contour < contour_limit; contour++ )
+ {
+ point = *contour;
+ end_point = point->prev;
+ first_point = point;
+
+ while ( point <= end_point && !( point->flags & touch_flag ) )
+ point++;
+
+ if ( point <= end_point )
{
- point->u = point->x;
- point->v = point->y;
+ AF_Point first_touched = point;
+ AF_Point cur_touched = point;
+
+
+ point++;
+ while ( point <= end_point )
+ {
+ if ( point->flags & touch_flag )
+ {
+ /* we found two successive touched points; we interpolate */
+ /* all contour points between them */
+ af_iup_interp( cur_touched + 1, point - 1,
+ cur_touched, point );
+ cur_touched = point;
+ }
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ {
+ /* this is a special case: only one point was touched in the */
+ /* contour; we thus simply shift the whole contour */
+ af_iup_shift( first_point, end_point, cur_touched );
+ }
+ else
+ {
+ /* now interpolate after the last touched point to the end */
+ /* of the contour */
+ af_iup_interp( cur_touched + 1, end_point,
+ cur_touched, first_touched );
+
+ /* if the first contour point isn't touched, interpolate */
+ /* from the contour start to the first touched point */
+ if ( first_touched > points )
+ af_iup_interp( first_point, first_touched - 1,
+ cur_touched, first_touched );
+ }
}
}
+
+ /* now save the interpolated values back to x/y */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->x = point->u;
+ }
+ else
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->y = point->u;
+ }
}
+
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -6,8 +6,8 @@
FT_BEGIN_HEADER
/*
- * The definition of outline hints. These are shared by all
- * script analysis routines
+ * The definition of outline glyph hints. These are shared by all
+ * script analysis routines (until now)
*
*/
@@ -17,7 +17,7 @@
AF_DIMENSION_VERT = 1, /* y coordinates, i.e. horizontal segments & edges */
AF_DIMENSION_MAX /* do not remove */
-
+
} AF_Dimension;
@@ -30,7 +30,7 @@
AF_DIR_LEFT = -1,
AF_DIR_UP = 2,
AF_DIR_DOWN = -2
-
+
} AF_Direction;
@@ -38,33 +38,33 @@
typedef enum
{
AF_FLAG_NONE = 0,
-
+
/* point type flags */
AF_FLAG_CONIC = (1 << 0),
AF_FLAG_CUBIC = (1 << 1),
AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC,
-
+
/* point extremum flags */
AF_FLAG_EXTREMA_X = (1 << 2),
AF_FLAG_EXTREMA_Y = (1 << 3),
-
+
/* point roundness flags */
AF_FLAG_ROUND_X = (1 << 4),
AF_FLAG_ROUND_Y = (1 << 5),
-
+
/* point touch flags */
AF_FLAG_TOUCH_X = (1 << 6),
AF_FLAG_TOUCH_Y = (1 << 7),
-
+
/* candidates for weak interpolation have this flag set */
AF_FLAG_WEAK_INTERPOLATION = (1 << 8),
-
+
/* all inflection points in the outline have this flag set */
AF_FLAG_INFLECTION = (1 << 9)
-
+
} AF_Flags;
-
+
/* edge hint flags */
typedef enum
{
@@ -72,7 +72,7 @@
AF_EDGE_ROUND = (1 << 0),
AF_EDGE_SERIF = (1 << 1),
AF_EDGE_DONE = (1 << 2)
-
+
} AF_Edge_Flags;
@@ -110,10 +110,10 @@
AF_Edge edge; /* the segment's parent edge */
AF_Segment edge_next; /* link to next segment in parent edge */
- AF_Segment link; /* link segment */
+ AF_Segment link; /* (stem) link segment */
AF_Segment serif; /* primary segment for serifs */
FT_Pos num_linked; /* number of linked segments */
- FT_Pos score;
+ FT_Pos score; /* used during stem matching */
AF_Point first; /* first point in edge segment */
AF_Point last; /* last point in edge segment */
@@ -131,7 +131,7 @@
AF_Edge_Flags flags; /* edge flags */
AF_Direction dir; /* edge direction */
FT_Fixed scale; /* used to speed up interpolation between edges */
- FT_Pos* blue_edge; /* non-NULL if this is a blue edge */
+ AF_Width blue_edge; /* non-NULL if this is a blue edge */
AF_Edge link;
AF_Edge serif;
@@ -142,7 +142,6 @@
AF_Segment first;
AF_Segment last;
-
} AF_EdgeRec;
@@ -150,7 +149,7 @@
{
FT_Int num_segments;
AF_Segment segments;
-
+
FT_Int num_edges;
AF_Edge edges;
@@ -158,8 +157,8 @@
} AF_AxisHintsRec, *AF_AxisHints;
-
- typedef struct AF_OutlineHintsRec_
+
+ typedef struct AF_GlyphHintsRec_
{
FT_Memory memory;
@@ -177,7 +176,7 @@
AF_AxisHintsRec axis[ AF_DIMENSION_MAX ];
- } AF_OutlineHintsRec;
+ } AF_GlyphHintsRec;
@@ -188,43 +187,36 @@
FT_LOCAL( void )
- af_outline_hints_init( AF_OutlineHints hints );
+ af_glyph_hints_init( AF_GlyphHints hints,
+ FT_Memory memory );
- /* used to set the (u,v) fields of each AF_Point in a AF_OutlineHints
- * object.
- */
- typedef enum AH_UV_
- {
- AH_UV_FXY, /* (u,v) = (fx,fy) */
- AH_UV_FYX, /* (u,v) = (fy,fx) */
- AH_UV_OXY, /* (u,v) = (ox,oy) */
- AH_UV_OYX, /* (u,v) = (oy,ox) */
- AH_UV_OX, /* (u,v) = (ox,x) */
- AH_UV_OY, /* (u,v) = (oy,y) */
- AH_UV_YX, /* (u,v) = (y,x) */
- AH_UV_XY /* (u,v) = (x,y) * should always be last! */
- } AH_UV;
-
- FT_LOCAL_DEF( void )
- af_outline_hints_setup_uv( AF_OutlineHints hints,
- AF_UV source );
-
-
- /* recomputes all AF_Point in a AF_OutlineHints from the definitions
+ /* recomputes all AF_Point in a AF_GlyphHints from the definitions
* in a source outline
*/
FT_LOCAL( FT_Error )
- af_outline_hints_reset( AF_OutlineHints hints,
- FT_Outline* outline,
- FT_Fixed x_scale,
- FT_Fixed y_scale );
+ af_glyph_hints_reset( AF_GlyphHints hints,
+ FT_Outline* outline,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale,
+ FT_Pos x_delta,
+ FT_Pos y_delta );
FT_LOCAL( void )
- af_outline_hints_done( AF_OutlineHints hints );
+ af_glyph_hints_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+ FT_LOCAL( void )
+ af_glyph_hints_align_strong_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+ FT_LOCAL( void )
+ af_glyph_hints_align_weak_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_glyph_hints_done( AF_GlyphHints hints );
/* */
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -1,9 +1,439 @@
#include "aflatin.h"
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N G L O B A L M E T R I C S *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ static void
+ af_latin_metrics_init_widths( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ /* scan the array of segments in each direction */
+ AF_GlyphHintsRec hints[1];
+
+ af_glyph_hints_init( hints, face->memory );
+
+ metrics->axis[ AF_DIMENSION_HORZ ].width_count = 0;
+ metrics->axis[ AF_DIMENSION_VERT ].width_count = 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;
+ AF_Dimension dim;
+
+
+ glyph_index = FT_Get_Char_Index( face, 'o' );
+ if ( glyph_index == 0 )
+ goto Exit;
+
+ error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || face->glyph->outline.n_points <= 0 )
+ goto Exit;
+
+ error = af_glyph_hints_reset( hints, &face->glyph->outline,
+ 0x10000L, 0x10000L );
+ if ( error )
+ goto Exit;
+
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_LatinAxis axis = & metrics->axis[ dim ];
+ AF_AxisHints axhints = & hints->axis[ dim ];
+ AF_Segment seg, limit, link;
+ FT_UInt num_widths = 0;
+ FT_Pos edge_distance_threshold = 32000;
+
+ af_latin_hints_compute_segments( hints, dim );
+ af_latin_hints_link_segments ( hints, dim );
+
+ seg = axhints->segments;
+ limit = seg + axhints->num_segments;
+
+ for ( ; seg < limit; seg++ )
+ {
+ link = seg->link;
+ /* we only consider stem segments there! */
+ if ( link && link->link == seg && link > seg )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - link->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( num_widths < AF_LATIN_MAX_WIDTHS )
+ axis->widths[ num_widths++ ] = dist;
+ }
+ }
+
+ af_sort_pos( axis->widths, num_widths );
+ axis->width_count = num_widths;
+
+ /* we will now try to find the smallest width */
+ if ( num_widths > 0 && axis->widths[0] < edge_distance_threshold )
+ edge_distance_threshold = axis->widths[0];
+
+ /* 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% */
+ axis->edge_distance_threshold = edge_distance_threshold / 5;
+ }
+ }
+
+ Exit:
+ af_glyph_hints_done( hints );
+ }
+
+
+
+#define AF_LATIN_MAX_TEST_CHARACTERS 12
+
+
+ static const char* const af_latin_blue_chars[ AF_LATIN_MAX_BLUES ] =
+ {
+ "THEZOCQS",
+ "HEZLOCUS",
+ "fijkdbh",
+ "xzroesc",
+ "xzroesc",
+ "pqgjy"
+ };
+
+
+ static void
+ af_latin_metrics_init_blues( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Pos flats [ AF_LATIN_MAX_TEST_CHARACTERS ];
+ FT_Pos rounds[ AF_LATIN_MAX_TEST_CHARACTERS ];
+ FT_Int num_flats;
+ FT_Int num_rounds;
+ FT_Int bb;
+ AF_LatinBlue blue;
+ FT_Error error;
+ AF_LatinAxis axis = &metrics->axis[ AF_DIMENSION_VERT ];
+ FT_GlyphSlot glyph = face->glyph;
+
+ /* we compute the blues simply by loading each character from the */
+ /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
+ /* bottom-most points (depending on `AF_IS_TOP_BLUE') */
+
+ AF_LOG(( "blue zones computation\n" ));
+ AF_LOG(( "------------------------------------------------\n" ));
+
+ for ( bb = 0; bb < AF_BLUE_MAX; bb++ )
+ {
+ const char* p = af_latin_blue_chars[bb];
+ const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
+ FT_Pos* blue_ref;
+ FT_Pos* blue_shoot;
+
+ AF_LOG(( "blue %3d: ", blue ));
+
+ num_flats = 0;
+ num_rounds = 0;
+
+ for ( ; p < limit && *p; p++ )
+ {
+ FT_UInt glyph_index;
+ FT_Vector* extremum;
+ FT_Vector* points;
+ FT_Vector* point_limit;
+ FT_Vector* point;
+ FT_Bool round;
+
+
+ AF_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 ( AF_IS_TOP_BLUE( bb ) )
+ {
+ 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;
+ }
+
+ AF_LOG(( "%5d", (int)extremum->y ));
+
+ /* now, check whether 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 idx = (FT_Int)( extremum - points );
+ FT_Int n;
+ FT_Int first, 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 >= idx )
+ {
+ 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 = idx;
+ next = prev;
+
+ do
+ {
+ if ( prev > first )
+ prev--;
+ else
+ prev = last;
+
+ dist = points[prev].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( prev != idx );
+
+ do
+ {
+ if ( next < last )
+ next++;
+ else
+ next = first;
+
+ dist = points[next].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( next != idx );
+
+ /* now, set the `round' flag depending on the segment's kind */
+ round = FT_BOOL(
+ FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+ FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+
+ AF_LOG(( "%c ", round ? 'r' : 'f' ));
+ }
+
+ if ( round )
+ rounds[num_rounds++] = extremum->y;
+ else
+ flats[num_flats++] = extremum->y;
+ }
+
+ AF_LOG(( "\n" ));
+
+ if ( num_flats == 0 && num_rounds == 0 )
+ {
+ /* we couldn't find a single glyph to compute this blue zone,
+ * we will simply ignore it then
+ */
+ AF_LOG(( "empty !!\n" ));
+ continue;
+ }
+
+ /* 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 sort */
+ af_sort_pos( num_rounds, rounds );
+ af_sort_pos( num_flats, flats );
+
+ blue = axis->blues[ axis->blue_count ];
+ blue_ref = & blue->ref.org;
+ blue_shoot = & blue->shoot.org;
+
+ axis->blue_count ++;
+
+ 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: if 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 = FT_BOOL( shoot > ref );
+
+
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
+ *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ }
+
+ blue->flags = 0;
+ if ( AF_LATIN_IS_TOP_BLUE(bb) )
+ blue->flags |= AF_LATIN_BLUE_TOP;
+
+ AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ }
+
+ Exit:
+ return;
+ }
+
+
+ static FT_Error
+ af_latin_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Error error;
+ FT_CharMap oldmap = face->charmap;
+
+ /* do we have a Unicode charmap in there? */
+ error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+ if ( error ) goto Exit;
+
+ metrics->units_per_em = face->units_per_EM;
+
+ af_latin_metrics_init_widths( metrics, face );
+ af_latin_metrics_init_blues( metrics, face );
+
+ Exit:
+ FT_Set_Charmap( face, oldmap );
+ return error;
+ }
+
+
+ static void
+ af_latin_metrics_scale_dim( AF_LatinMetrics metrics,
+ AF_Scaler scaler,
+ AF_Dimension dim )
+ {
+ FT_Fixed scale;
+ FT_Pos delta;
+ AF_LatinAxis axis;
+ FT_UInt nn;
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ scale = scaler->x_scale;
+ delta = scaler->x_delta;
+ }
+ else
+ {
+ scale = scaler->y_scale;
+ delta = scaler->y_delta;
+ }
+
+ axis = metrics->axis[ dim ];
+
+ if ( axis->scale == scale && axis->delta == delta )
+ return;
+
+ axis->scale = scale;
+ axis->delta = delta;
+
+ /* scale the standard widths
+ */
+ for ( nn = 0; nn < axis->width_count; nn++ )
+ {
+ AF_Width width = axis->widths + nn;
+
+ width->cur = FT_MulFix( width->org, scale );
+ width->fit = width->cur;
+ }
+
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ /* scale the blue zones
+ */
+ for ( nn = 0; nn < axis->blue_count; nn++ )
+ {
+ AF_LatinBlue blue = & axis->blues[nn];
+ FT_UInt flags = blue->flags & ~AF_LATIN_BLUE_ACTIVE;
+ FT_Pos dist;
+
+ blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
+ blue->ref.fit = blue->ref.cur;
+
+ blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
+ blue->shoot.fit = blue->shoot.cur;
+
+ /* a blue zone is only active when it is less than 3/4 pixels tall
+ */
+ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
+ if ( dist >= 48 || dist <= -48 )
+ blue->flags |= ~AF_LATIN_BLUE_ACTIVE;
+ }
+ }
+ }
+
+
FT_LOCAL_DEF( void )
- af_latin_hints_compute_segments( AF_OutlineHints hints,
- AF_Dimension dim )
+ af_latin_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler )
{
+ af_latin_metrics_scale( metrics, scaler, AF_DIMENSION_HORZ );
+ af_latin_metrics_scale( metrics, scaler, AF_DIMENSION_VERT );
+ }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
AF_AxisHints axis = &hints->axis[dim];
AF_Segment segments = axis->segments;
AF_Segment segment = segments;
@@ -23,11 +453,30 @@
segment_dir = major_dir;
/* set up (u,v) in each point */
- af_setup_uv( outline, (dim == AF_DIMENSION_HORZ)
- ? AF_UV_FXY,
- : AF_UV_FYX );
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fx;
+ point->v = point->fy;
+ }
+ }
+ else
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fy;
+ point->v = point->fx;
+ }
+ }
+
+
/* do each contour separately */
for ( ; contour < contour_limit; contour++ )
{
@@ -238,8 +687,8 @@
FT_LOCAL_DEF( void )
- af_latin_hints_link_segments( AF_OutlineHints hints,
- AF_Dimension dim )
+ af_latin_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
AF_Segment segments = axis->segments;
@@ -318,17 +767,17 @@
FT_LOCAL_DEF( void )
- af_latin_hints_compute_edges( AF_OutlineHints hints,
- AF_Dimension dim )
+ af_latin_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
AF_Edge edges = axis->edges;
AF_Edge edge, edge_limit;
-
+
AF_Segment segments = axis->segments;
AF_Segment segment_limit = segments + axis->num_segments;
AF_Segment seg;
-
+
AF_Direction up_dir;
FT_Fixed scale;
FT_Pos edge_distance_threshold;
@@ -519,7 +968,6 @@
else
edge2 = seg2->edge;
-#ifdef FT_CONFIG_CHESTER_SERIF
if ( is_serif )
{
edge->serif = edge2;
@@ -527,12 +975,6 @@
}
else
edge->link = edge2;
-#else /* !FT_CONFIG_CHESTER_SERIF */
- if ( is_serif )
- edge->serif = edge2;
- else
- edge->link = edge2;
-#endif /* !FT_CONFIG_CHESTER_SERIF */
}
seg = seg->edge_next;
@@ -567,17 +1009,9 @@
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* af_outline_detect_features */
- /* */
- /* <Description> */
- /* Performs feature detection on a given AF_OutlineRec object. */
- /* */
FT_LOCAL_DEF( void )
- af_latin_hints_detect_features( AF_OutlineHints hints,
- AF_Dimension dim )
+ af_latin_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim )
{
af_latin_hints_compute_segments( hints, dim );
af_latin_hints_link_segments ( hints, dim );
@@ -585,93 +1019,51 @@
}
- /*************************************************************************/
- /* */
- /* <Function> */
- /* af_outline_compute_blue_edges */
- /* */
- /* <Description> */
- /* Computes the `blue edges' in a given outline (i.e. those that must */
- /* be snapped to a blue zone edge (top or bottom). */
- /* */
FT_LOCAL_DEF( void )
- af_latin_hints_compute_blue_edges( AF_OutlineHints outline,
- AF_Face_Globals face_globals )
+ af_latin_hints_compute_blue_edges( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
{
- AF_Edge edge = outline->horz_edges;
- AF_Edge edge_limit = edge + outline->num_hedges;
- AF_Globals globals = &face_globals->design;
- FT_Fixed y_scale = outline->y_scale;
+ AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
+ AF_Edge edge = axis->edges;
+ AF_Edge edge_limit = edge + axis->num_edges;
+ AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ];
+ FT_Fixed scale = latin->scale;
- FT_Bool blue_active[AF_BLUE_MAX];
-
/* compute which blue zones are active, i.e. have their scaled */
/* size < 3/4 pixels */
- {
- AF_Blue blue;
- FT_Bool check = 0;
-
- for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
- {
- FT_Pos ref, shoot, dist;
-
-
- ref = globals->blue_refs[blue];
- shoot = globals->blue_shoots[blue];
- dist = ref - shoot;
- if ( dist < 0 )
- dist = -dist;
-
- blue_active[blue] = 0;
-
- if ( FT_MulFix( dist, y_scale ) < 48 )
- {
- blue_active[blue] = 1;
- check = 1;
- }
- }
-
- /* return immediately if no blue zone is active */
- if ( !check )
- return;
- }
-
- /* for each horizontal edge search the blue zone which is closest */
+ /* for each horizontal edge search the blue zone which is closest */
for ( ; edge < edge_limit; edge++ )
{
- AF_Blue blue;
- FT_Pos* best_blue = 0;
- FT_Pos best_dist; /* initial threshold */
+ FT_Int bb;
+ AF_Width best_blue = NULL;
+ FT_Pos best_dist; /* initial threshold */
/* compute the initial threshold as a fraction of the EM size */
- best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+ best_dist = FT_MulFix( metrics->units_pe_EM / 40, scale );
-#ifdef FT_CONFIG_CHESTER_SMALL_F
if ( best_dist > 64 / 2 )
best_dist = 64 / 2;
-#else
- if ( best_dist > 64 / 4 )
- best_dist = 64 / 4;
-#endif
- for ( blue = AF_BLUE_CAPITAL_TOP; blue < AF_BLUE_MAX; blue++ )
+ for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
{
+ AF_LatinBlue blue = latin->blues + bb;
+ FT_Bool is_top_blue, is_major_dir;
+
+ /* skip inactive blue zones (i.e. those that are too small
+ */
+ if ( !(bb->flags & AF_LATIN_BLUE_ACTIVE) )
+ continue;
+
/* if it is a top zone, check for right edges -- if it is a bottom */
/* zone, check for left edges */
/* */
/* of course, that's for TrueType XXX */
- FT_Bool is_top_blue =
- FT_BOOL( AF_IS_TOP_BLUE( blue ) );
- FT_Bool is_major_dir =
- FT_BOOL( edge->dir == outline->horz_major_dir );
+ is_top_blue = (bb->flags & AF_LATIN_BLUE_TOP) != 0;
+ is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
-
- if ( !blue_active[blue] )
- continue;
-
/* if it is a top zone, the edge must be against the major */
/* direction; if it is a bottom zone, it must be in the major */
/* direction */
@@ -678,11 +1070,10 @@
if ( is_top_blue ^ is_major_dir )
{
FT_Pos dist;
- FT_Pos* blue_pos = globals->blue_refs + blue;
/* first of all, compare it to the reference position */
- dist = edge->fpos - *blue_pos;
+ dist = edge->fpos - blue->ref.org;
if ( dist < 0 )
dist = -dist;
@@ -690,7 +1081,7 @@
if ( dist < best_dist )
{
best_dist = dist;
- best_blue = blue_pos;
+ best_blue = & blue->ref;
}
/* now, compare it to the overshoot position if the edge is */
@@ -698,13 +1089,13 @@
/* top zone, or under the reference position of a bottom zone */
if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
{
- FT_Bool is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
if ( is_top_blue ^ is_under_ref )
{
- blue_pos = globals->blue_shoots + blue;
- dist = edge->fpos - *blue_pos;
+ blue = _pos = globals->blue_shoots + blue;
+ dist = edge->fpos - blue->shoot.org;
if ( dist < 0 )
dist = -dist;
@@ -712,7 +1103,7 @@
if ( dist < best_dist )
{
best_dist = dist;
- best_blue = blue_pos;
+ best_blue = & blue->shoot;
}
}
}
@@ -725,31 +1116,600 @@
}
+ static FT_Error
+ af_latin_hints_init( AF_GlyphHints hints,
+ AF_Scaler scaler,
+ AF_LatinMetrics metrics )
+ {
+ FT_Error error;
+
+ error = af_glyph_hints_reset( hints, &scaler->outline,
+ scaler->x_scale,
+ scaler->y_scale,
+ scaler->x_delta,
+ scaler->y_delta );
+ if (error)
+ goto Exit;
+
+ af_latin_hints_detect_features( hints, metrics );
+ af_latin_hints_compute_blue_edges( hints, metrics );
+
+ Exit:
+ return error;
+ }
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+ static FT_Pos
+ af_latin_snap_width( AF_Width widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+ FT_Pos scaled;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n].cur;
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ scaled = ( reference + 32 ) & -64;
+
+ if ( width >= reference )
+ {
+ if ( width < scaled + 48 )
+ width = reference;
+ }
+ else
+ {
+ if ( width > scaled - 48 )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* compute the snapped width of a given stem */
+
+ static FT_Pos
+ af_latin_compute_stem_width( AF_GylphHints hints,
+ AF_Dimension dim,
+ FT_Pos width,
+ AF_Edge_Flags base_flags,
+ AF_Edge_Flags stem_flags )
+ {
+ AF_Globals globals = &hinter->globals->scaled;
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+ FT_Bool vertical = FT_BOOL( dim == AF_DIMENSION_VERT );
+
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
+
+ if ( !hinter->do_stem_adjust )
+ {
+ /* leave stem widths unchanged */
+ }
+ else if ( ( vertical && !hinter->do_vert_snapping ) ||
+ ( !vertical && !hinter->do_horz_snapping ) )
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+ /* */
+
+ /* leave the widths of serifs alone */
+
+ if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
+ goto Done_Width;
+
+ else if ( ( base_flags & AF_EDGE_ROUND ) )
+ {
+ if ( dist < 80 )
+ dist = 64;
+ }
+ else if ( dist < 56 )
+ dist = 56;
+
+ {
+ FT_Pos delta = dist - globals->stds[vertical];
+
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ dist = globals->stds[vertical];
+ if ( dist < 48 )
+ dist = 48;
+
+ goto Done_Width;
+ }
+
+ if ( dist < 3 * 64 )
+ {
+ delta = dist & 63;
+ dist &= -64;
+
+ if ( delta < 10 )
+ dist += delta;
+
+ else if ( delta < 32 )
+ dist += 10;
+
+ else if ( delta < 54 )
+ dist += 54;
+
+ else
+ dist += delta;
+ }
+ else
+ dist = ( dist + 32 ) & -64;
+ }
+ }
+ else
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+ /* */
+ if ( vertical )
+ {
+ dist = af_snap_width( globals->heights, globals->num_heights, dist );
+
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & -64;
+ else
+ dist = 64;
+ }
+ else
+ {
+ dist = af_snap_width( globals->widths, globals->num_widths, dist );
+
+ if ( hinter->flags & AF_HINTER_MONOCHROME )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & -64;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ dist = ( dist + 22 ) & -64;
+ else
+ /* XXX: round otherwise to prevent color fringes in LCD mode */
+ dist = ( dist + 32 ) & -64;
+ }
+ }
+ }
+
+ Done_Width:
+ if ( sign )
+ dist = -dist;
+
+ return dist;
+ }
+
+
+
+ /* align one stem edge relative to the previous stem edge */
+ static void
+ af_latin_align_linked_edge( AF_GlyphHints hints,
+ AF_Dimension dim,
+ AF_Edge base_edge,
+ AF_Edge stem_edge )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+
+ FT_Pos fitted_width = af_latin_compute_stem_width( hints,
+ dim,
+ dist,
+ base_edge->flags,
+ stem_edge->flags );
+
+ stem_edge->pos = base_edge->pos + fitted_width;
+ }
+
+
+ static void
+ af_latin_align_serif_edge( AF_GlyphHints hints,
+ AF_Edge base,
+ AF_Edge serif )
+ {
+ FT_UNUSED( hints );
+
+ serif->pos = base->pos + (serif->opos - base->opos);
+ }
+
/*************************************************************************/
- /* */
- /* <Function> */
- /* af_outline_scale_blue_edges */
- /* */
- /* <Description> */
- /* This function must be called before hinting in order to re-adjust */
- /* the contents of the detected edges (basically change the `blue */
- /* edge' pointer from `design units' to `scaled ones'). */
- /* */
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
FT_LOCAL_DEF( void )
- af_outline_hints_scale_blue_edges( AF_OutlineHints hints ) outline,
+ af_latin_hint_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
{
- AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
- AF_Edge edge = axis->edges;
- AF_Edge edge_limit = edge + axis->num_edges;
- FT_Pos delta;
+ AF_AxisHints axis = & hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ FT_Int n_edges;
+ AF_Edge edge;
+ AF_Edge anchor = 0;
+ FT_Int has_serifs = 0;
- delta = globals->scaled.blue_refs - globals->design.blue_refs;
+ /* we begin by aligning all stems relative to the blue zone */
+ /* if needed -- that's only for horizontal edges */
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Width* blue;
+ AF_Edge edge1, edge2;
- for ( ; edge < edge_limit; edge++ )
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ blue = edge->blue_edge;
+ edge1 = NULL;
+ edge2 = edge->link;
+
+ if ( blue )
+ {
+ edge1 = edge;
+ }
+ else if ( edge2 && edge2->blue_edge )
+ {
+ blue = edge2->blue_edge;
+ edge1 = edge2;
+ edge2 = edge;
+ }
+
+ if ( !edge1 )
+ continue;
+
+ edge1->pos = blue->fit;
+ edge1->flags |= AF_EDGE_DONE;
+
+ if ( edge2 && !edge2->blue_edge )
+ {
+ af_latin_align_linked_edge( hints, dim, edge1, edge2 );
+ edge2->flags |= AF_EDGE_DONE;
+ }
+
+ if ( !anchor )
+ anchor = edge;
+ }
+ }
+
+ /* now we will align all stem edges, trying to maintain the */
+ /* relative order of stems in the glyph */
+ for ( edge = edges; edge < edge_limit; edge++ )
{
- if ( edge->blue_edge )
- edge->blue_edge += delta;
+ AF_Edge edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ has_serifs++;
+ continue;
+ }
+
+ /* now align the stem */
+
+ /* this should not happen, but it's better to be safe */
+ if ( edge2->blue_edge || edge2 < edge )
+ {
+ af_latin_align_linked_edge( hinter, edge2, edge, dimension );
+ edge->flags |= AF_EDGE_DONE;
+ continue;
+ }
+
+ if ( !anchor )
+ {
+ FT_Pos org_len, org_center, cur_len;
+ FT_Pos cur_pos1, error1, error2, u_off, d_off;
+
+
+ org_len = edge2->opos - edge->opos;
+ cur_len = af_latin_compute_stem_width( hints, dim, org_len,
+ edge->flags, edge2->flags );
+ if ( cur_len <= 64 )
+ u_off = d_off = 32;
+ else
+ {
+ u_off = 38;
+ d_off = 26;
+ }
+
+ if ( cur_len < 96 )
+ {
+ org_center = edge->opos + ( org_len >> 1 );
+
+ cur_pos1 = ( org_center + 32 ) & -64;
+
+ error1 = org_center - ( cur_pos1 - u_off );
+ if ( error1 < 0 )
+ error1 = -error1;
+
+ error2 = org_center - ( cur_pos1 + d_off );
+ if ( error2 < 0 )
+ error2 = -error2;
+
+ if ( error1 < error2 )
+ cur_pos1 -= u_off;
+ else
+ cur_pos1 += d_off;
+
+ edge->pos = cur_pos1 - cur_len / 2;
+ edge2->pos = cur_pos1 + cur_len / 2;
+
+ }
+ else
+ edge->pos = ( edge->opos + 32 ) & -64;
+
+ anchor = edge;
+
+ edge->flags |= AF_EDGE_DONE;
+
+ af_latin_align_linked_edge( hints, dim, edge, edge2 );
+ }
+ else
+ {
+ FT_Pos org_pos, org_len, org_center, cur_len;
+ FT_Pos cur_pos1, cur_pos2, delta1, delta2;
+
+
+ org_pos = anchor->pos + ( edge->opos - anchor->opos );
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = af_compute_stem_width( hinter, dimension, org_len,
+ edge->flags, edge2->flags );
+
+ if ( cur_len < 96 )
+ {
+ FT_Pos u_off, d_off;
+
+
+ cur_pos1 = ( org_center + 32 ) & -64;
+
+ if (cur_len <= 64 )
+ u_off = d_off = 32;
+ else
+ {
+ u_off = 38;
+ d_off = 26;
+ }
+
+ delta1 = org_center - ( cur_pos1 - u_off );
+ if ( delta1 < 0 )
+ delta1 = -delta1;
+
+ delta2 = org_center - ( cur_pos1 + d_off );
+ if ( delta2 < 0 )
+ delta2 = -delta2;
+
+ if ( delta1 < delta2 )
+ cur_pos1 -= u_off;
+ else
+ cur_pos1 += d_off;
+
+ edge->pos = cur_pos1 - cur_len / 2;
+ edge2->pos = cur_pos1 + cur_len / 2;
+ }
+ else
+ {
+ org_pos = anchor->pos + ( edge->opos - anchor->opos );
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = af_compute_stem_width( hinter, dimension, org_len,
+ edge->flags, edge2->flags );
+
+ cur_pos1 = ( org_pos + 32 ) & -64;
+ delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
+ if ( delta1 < 0 )
+ delta1 = -delta1;
+
+ cur_pos2 = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
+ delta2 = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
+ if ( delta2 < 0 )
+ delta2 = -delta2;
+
+ edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
+ edge2->pos = edge->pos + cur_len;
+ }
+
+ edge->flags |= AF_EDGE_DONE;
+ edge2->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+ }
}
+
+ /* make sure that lowercase m's maintain their symmetry */
+
+ /* In general, lowercase m's have six vertical edges if they are sans */
+ /* serif, or twelve if they are avec serif. This implementation is */
+ /* based on that assumption, and seems to work very well with most */
+ /* faces. However, if for a certain face this assumption is not */
+ /* true, the m is just rendered like before. In addition, any stem */
+ /* correction will only be applied to symmetrical glyphs (even if the */
+ /* glyph is not an m), so the potential for unwanted distortion is */
+ /* relatively low. */
+
+ /* We don't handle horizontal edges since we can't easily assure that */
+ /* the third (lowest) stem aligns with the base line; it might end up */
+ /* one pixel higher or lower. */
+
+ n_edges = edge_limit - edges;
+ if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
+ {
+ AF_Edge edge1, edge2, edge3;
+ FT_Pos dist1, dist2, span, delta;
+
+
+ if ( n_edges == 6 )
+ {
+ edge1 = edges;
+ edge2 = edges + 2;
+ edge3 = edges + 4;
+ }
+ else
+ {
+ edge1 = edges + 1;
+ edge2 = edges + 5;
+ edge3 = edges + 9;
+ }
+
+ dist1 = edge2->opos - edge1->opos;
+ dist2 = edge3->opos - edge2->opos;
+
+ span = dist1 - dist2;
+ if ( span < 0 )
+ span = -span;
+
+ if ( span < 8 )
+ {
+ delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
+ edge3->pos -= delta;
+ if ( edge3->link )
+ edge3->link->pos -= delta;
+
+ /* move the serifs along with the stem */
+ if ( n_edges == 12 )
+ {
+ ( edges + 8 )->pos -= delta;
+ ( edges + 11 )->pos -= delta;
+ }
+
+ edge3->flags |= AF_EDGE_DONE;
+ if ( edge3->link )
+ edge3->link->flags |= AF_EDGE_DONE;
+ }
+ }
+
+ if ( has_serifs || !anchor )
+ {
+ /* now hint the remaining edges (serifs and single) in order
+ * to complete our processing
+ */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ if ( edge->serif )
+ af_align_serif_edge( hinter, edge->serif, edge, dimension );
+ else if ( !anchor )
+ {
+ edge->pos = ( edge->opos + 32 ) & -64;
+ anchor = edge;
+ }
+ else
+ edge->pos = anchor->pos +
+ ( ( edge->opos-anchor->opos + 32 ) & -64 );
+
+ edge->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+
+ if ( edge + 1 < edge_limit &&
+ edge[1].flags & AF_EDGE_DONE &&
+ edge->pos > edge[1].pos )
+ edge->pos = edge[1].pos;
+ }
+ }
}
+
+
+ static FT_Error
+ af_latin_hints_apply( AF_GlyphHints hints,
+ AF_Scaler scaler,
+ AF_LatinMetrics metrics )
+ {
+ /* XXX */
+ return FT_Err_Unimplemented;
+ }
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N S C R I P T C L A S S *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ static const AF_Script_UniRangeRec af_latin_uniranges[] =
+ {
+ { 32, 127 }, /* XXX: TODO: Add new Unicode ranges here !! */
+ { 160, 255 },
+ { 0, 0 }
+ };
+
+ FT_LOCAL_DEF( const AF_ScriptClassRec ) af_latin_script_class =
+ {
+ AF_SCRIPT_LATIN,
+ &af_latin_script_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+ (AF_Script_InitMetricsFunc) af_latin_metrics_init,
+ (AF_Script_ScaleMetricsFunc) af_latin_metrics_scale,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_latin_hints_init,
+ (AF_Script_ApplyHintsFunc) af_latin_hints_apply
+ };
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -11,6 +11,14 @@
*/
FT_LOCAL( const FT_ScriptClassRec ) af_latin_script_class;
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N G L O B A L M E T R I C S *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
/*
* the following declarations could be embedded in the file "aflatin.c"
* they've been made semi-public to allow alternate script hinters to
@@ -21,29 +29,65 @@
* Latin (global) metrics management
*
*/
-
+
+ enum
+ {
+ AF_LATIN_BLUE_CAPITAL_TOP,
+ AF_LATIN_BLUE_CAPITAL_BOTTOM,
+ AF_LATIN_BLUE_SMALL_F_TOP,
+ AF_LATIN_BLUE_SMALL_TOP,
+ AF_LATIN_BLUE_SMALL_BOTTOM,
+ AF_LATIN_BLUE_SMALL_MINOR,
+
+ AF_LATIN_BLUE_MAX
+ };
+
+#define AF_LATIN_IS_TOP_BLUE( b ) ( (b) == AF_LATIN_BLUE_CAPITAL_TOP || \
+ (b) == AF_LATIN_BLUE_SMALL_F_TOP || \
+ (b) == AF_LATIN_BLUE_SMALL_TOP )
+
#define AF_LATIN_MAX_WIDTHS 16
-#define AF_LATIN_MAX_BLUES 32
+#define AF_LATIN_MAX_BLUES AF_LATIN_BLUE_MAX
+ enum
+ {
+ AF_LATIN_BLUE_ACTIVE = (1 << 0),
+ AF_LATIN_BLUE_TOP = (1 << 1),
+
+ AF_LATIN_BLUE_MAX
+ };
+
+
+ typedef struct AF_LatinBlueRec_
+ {
+ AF_WidthRec ref;
+ AF_WidthRec shoot;
+ FT_UInt flags;
+
+ } AF_LatinBlueRec, *AF_LatinBlue;
+
+
typedef struct AF_LatinAxisRec_
{
- FT_Fixed scale;
- FT_Pos delta;
+ FT_Fixed scale;
+ FT_Pos delta;
- FT_UInt width_count;
- AF_WidthRec widths[ AF_LATIN_MAX_WIDTHS ];
+ FT_UInt width_count;
+ AF_WidthRec widths[ AF_LATIN_MAX_WIDTHS ];
+ FT_Pos edge_distance_threshold;
/* ignored for horizontal metrics */
- FT_Bool control_overshoot;
- FT_UInt blue_count;
- AF_WidthRec blue_refs [ AF_MAX_BLUES ];
- AF_WidthRec blue_shoots[ AF_MAX_BLUES ];
-
+ FT_Bool control_overshoot;
+ FT_UInt blue_count;
+ AF_LatinBlueRec blues;
+
} AF_LatinAxisRec, *AF_LatinAxis;
-
+
+
typedef struct AF_LatinMetricsRec_
{
- AF_OutlineMetricsRec root;
+ AF_ScriptMetricsRec root;
+ FT_UInt units_per_em;
AF_LatinAxisRec axis[ AF_DIMENSION_MAX ];
} AF_LatinMetricsRec, *AF_LatinMetrics;
@@ -58,29 +102,40 @@
AF_Scaler scaler );
- /*
- * Latin (glyph) hints management
- *
- */
- FT_LOCAL(
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
- FT_LOCAL( void )
- af_latin_hints_compute_segments( AF_OutlineHints hints,
- AF_Dimension dim );
+ /* this shouldn't normally be exported. However, other scripts might
+ * like to use this function as-is
+ */
FT_LOCAL( void )
- af_latin_hints_link_segments( AF_OutlineHints hints,
- AF_Dimension dim );
+ af_latin_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+ /* this shouldn't normally be exported. However, other scripts might
+ * want to use this function as-is
+ */
FT_LOCAL( void )
- af_latin_hints_compute_edges( AF_OutlineHints hints,
- AF_Dimension dim );
+ af_latin_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+ /* this shouldn't normally be exported. However, other scripts might
+ * want to use this function as-is
+ */
FT_LOCAL( void )
- af_latin_hints_init( AF_OutlineHints hints,
- AF_Dimension dim );
+ af_latin_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim );
+ FT_LOCAL( void )
+ af_latin_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim );
/* */
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -1,6 +1,9 @@
#ifndef __AFTYPES_H__
#define __AFTYPES_H__
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
FT_BEGIN_HEADER
/**************************************************************************/
@@ -27,6 +30,27 @@
/**************************************************************************/
/**************************************************************************/
/***** *****/
+ /***** U T I L I T Y *****/
+ /***** *****/
+ /**************************************************************************/
+ /**************************************************************************/
+
+ typedef struct AF_WidthRec_
+ {
+ FT_Pos org; /* original position/width in font units */
+ FT_Pos cur; /* current/scaled position/width in device sub-pixels */
+ FT_Pos fit; /* current/fitted position/width in device sub-pixels */
+
+ } AF_WidthRec, *AF_Width;
+
+
+ AF_LOCAL( void )
+ af_sort_pos( FT_UInt count,
+ FT_Pos* table );
+
+ /**************************************************************************/
+ /**************************************************************************/
+ /***** *****/
/***** A N G L E T Y P E S *****/
/***** *****/
/**************************************************************************/
@@ -73,13 +97,17 @@
/**************************************************************************/
/**************************************************************************/
- typedef struct AF_OutlineHintsRec_* AF_OutlineHints;
+ /* opaque handle to glyph-specific hints. see "afhints.h" for more
+ * details
+ */
+ typedef struct AF_GlyphHintsRec_* AF_GlyphHints;
- typedef struct AF_GlobalHintsRec_* AF_GlobalHints;
-
+ /* this structure is used to model an input glyph outline to
+ * the auto-hinter. The latter will set the "hints" field
+ * depending on the glyph's script
+ */
typedef struct AF_OutlineRec_
{
- FT_Memory memory;
FT_Face face;
FT_OutlineRec outline;
FT_UInt outline_resolution;
@@ -87,54 +115,11 @@
FT_Int advance;
FT_UInt metrics_resolution;
- AF_OutlineHints hints;
+ AF_GlyphHints hints;
} AF_OutlineRec;
- /**************************************************************************/
- /**************************************************************************/
- /***** *****/
- /***** G L O B A L M E T R I C S *****/
- /***** *****/
- /**************************************************************************/
- /**************************************************************************/
- /*
- * the following define global metrics in a _single_ dimension
- *
- * the "blue_refs" and "blue_shoots" arrays are ignored in
- * the horizontal dimension
- */
-
- typedef struct AF_WidthRec_
- {
- FT_Pos org; /* original position/width in font units */
- FT_Pos cur; /* current/scaled position/width in device sub-pixels */
- FT_Pos fit; /* current/fitted position/width in device sub-pixels */
-
- } AF_WidthRec, *AF_Width;
-
-
-#define AF_MAX_WIDTHS 16
-#define AF_MAX_BLUES 32
-
- typedef struct AF_GlobalMetricsRec_
- {
- FT_Int num_widths;
- AF_WidthRec widths[ AF_MAX_WIDTHS ];
-
- FT_Fixed scale; /* used to scale from org to cur with: */
- FT_Pos delta; /* x_cur = x_org * scale + delta */
-
- /* ignored for horizontal metrics */
- AF_WidthRec blue_refs [ AF_MAX_BLUES ];
- AF_WidthRec blue_shoots[ AF_MAX_BLUES ];
-
- FT_Bool control_overshoot;
-
- } AF_GlobalMetricsRec, *AF_GlobalMetrics;
-
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -190,14 +175,20 @@
* - a specific global analyzer that will compute global metrics
* specific to the script.
*
- * - a specific hinting routine
+ * - a specific glyph analyzer that will compute segments and
+ * edges for each glyph covered by the script
*
- * all scripts should share the same analysis routine though
+ * - a specific grid-fitting algorithm that will distort the
+ * scaled glyph outline according to the results of the glyph
+ * analyzer
+ *
+ * note that a given analyzer and/or grid-fitting algorithm can be
+ * used by more than one script
*/
typedef enum
{
AF_SCRIPT_LATIN = 0,
- /* add new scripts here */
+ /* add new scripts here. don't forget to update the list in "afglobal.c" */
AF_SCRIPT_MAX /* do not remove */
@@ -204,16 +195,12 @@
} AF_Script;
+
typedef struct AF_ScriptClassRec_ const* AF_ScriptClass;
- /*
- * root class for script-specific metrics
- */
typedef struct AF_ScriptMetricsRec_
{
- AF_ScriptClass script_class;
- AF_GlobalMetricsRec horz_metrics;
- AF_GlobalMetricsRec vert_metrics;
+ AF_ScriptClass clazz;
} AF_ScriptMetricsRec, *AF_ScriptMetrics;
@@ -221,22 +208,24 @@
/* this function parses a FT_Face to compute global metrics for
* a specific script
*/
- typedef FT_Error (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics,
- FT_Face face );
+ typedef FT_Error (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics,
+ FT_Face face );
typedef void (*AF_Script_ScaleMetricsFunc)( AF_ScriptMetrics metrics,
AF_Scaler scaler );
- typedef void (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics metrics );
+ typedef void (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics metrics );
- typedef FT_Error (*AF_Script_InitHintsFunc)( AF_OutlineHints hints,
+ typedef FT_Error (*AF_Script_InitHintsFunc)( AF_GlyphHints hints,
AF_Scaler scaler,
AF_ScriptMetrics metrics );
- typedef void (*AF_Script_ApplyHintsFunc)( AF_OutlineHints hints );
-
+ typedef void (*AF_Script_ApplyHintsFunc)( AF_GlyphHints hints,
+ AF_Scaler scaler,
+ AF_ScriptMetrics metrics );
+
typedef struct AF_Script_UniRangeRec_
{
FT_UInt32 first;
@@ -248,7 +237,7 @@
typedef struct AF_ScriptClassRec_
{
AF_Script script;
- AF_Scipt_UniRange script_uni_ranges; /* last must be { 0, 0 } */
+ AF_Script_UniRange script_uni_ranges; /* last must be { 0, 0 } */
FT_UInt script_metrics_size;
AF_Script_InitMetricsFunc script_metrics_init;
@@ -255,33 +244,12 @@
AF_Script_ScaleMetricsFunc script_metrics_scale;
AF_Script_DoneMetricsFunc script_metrics_done;
+ AF_Script_InitHintsFunc script_hints_init;
+ AF_Script_ApplyHintsFunc script_hints_apply;
+
} AF_ScriptClassRec;
-
- /**************************************************************************/
- /**************************************************************************/
- /***** *****/
- /***** F A C E G L O B A L S *****/
- /***** *****/
- /**************************************************************************/
- /**************************************************************************/
-
- /*
- * models the global hints data for a given face, decomposed into
- * script-specific items..
- *
- */
- typedef struct AF_FaceGlobalsRec_
- {
- FT_Face face;
- FT_UInt glyph_count; /* same as face->num_glyphs */
- FT_Byte* glyph_scripts; /* maps each gindex to a script */
-
- FT_ScriptMetrics metrics[ AF_SCRIPT_MAX ];
-
- } AF_FaceGlobalsRec, *AF_FaceGlobals;
-
/* */
FT_END_HEADER