diff --git a/ChangeLog b/ChangeLog index 0269948e2..84fbdeaa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-11-22 David Turner + + * src/autofit/*: more updates + 2003-11-13 John A. Boyd Jr. * src/bdf/bdfdrivr.c (bdf_interpret_style), src/pcf/pcfread.c diff --git a/README b/README index bf99cfda6..72baf3d6a 100644 --- 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 diff --git a/builds/unix/configure.ac b/builds/unix/configure.ac index 90d21f6ef..89ba574aa 100644 --- a/builds/unix/configure.ac +++ b/builds/unix/configure.ac @@ -8,7 +8,7 @@ AC_CONFIG_SRCDIR([ftconfig.in]) # 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]) diff --git a/docs/VERSION.DLL b/docs/VERSION.DLL index 551fced44..9bdd643c7 100644 --- a/docs/VERSION.DLL +++ b/docs/VERSION.DLL @@ -52,6 +52,7 @@ systems, but not all of them: 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 diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h index 285d8efc9..0c6e67edf 100644 --- 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 diff --git a/src/autofit/afangles.c b/src/autofit/afangles.c index 66c7d7998..eb0a0425e 100644 --- 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 diff --git a/src/autofit/afglobal.c b/src/autofit/afglobal.c new file mode 100644 index 000000000..6f1540cc6 --- /dev/null +++ b/src/autofit/afglobal.c @@ -0,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; + } diff --git a/src/autofit/afglobal.h b/src/autofit/afglobal.h new file mode 100644 index 000000000..81b4800bc --- /dev/null +++ b/src/autofit/afglobal.h @@ -0,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__ */ diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c index b7d8efbbf..9becdd516 100644 --- a/src/autofit/afhints.c +++ b/src/autofit/afhints.c @@ -5,7 +5,7 @@ #include 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,34 +320,34 @@ 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 ) { 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,88 +538,400 @@ } /* compute inflection points - */ - af_outline_hints_compute_inflections( hints ); + */ + af_glyph_hints_compute_inflections( hints ); Exit: return error; } + + + /* + * + * E D G E P O I N T G R I D - F I T T I N G + * + */ + + FT_LOCAL_DEF( void ) - af_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++ ) - { - point->u = point->fx; - point->v = point->fy; - } - break; + /* move the points of each segment */ + /* in each edge to the edge's position */ + AF_Segment seg = edge->first; - case AF_UV_FYX: - for ( ; point < point_limit; point++ ) - { - point->u = point->fy; - point->v = point->fx; - } - break; - case AF_UV_OXY: - for ( ; point < point_limit; point++ ) + do { - point->u = point->ox; - point->v = point->oy; - } - break; + AF_Point point = seg->first; - case AF_UV_OYX: - for ( ; point < point_limit; point++ ) - { - point->u = point->oy; - point->v = point->ox; - } - break; - case AF_UV_YX: - for ( ; point < point_limit; point++ ) - { - point->u = point->y; - point->v = point->x; - } - break; + 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; + } - case AF_UV_OX: - for ( ; point < point_limit; point++ ) - { - point->u = point->x; - point->v = point->ox; - } - break; + if ( point == seg->last ) + break; - case AF_UV_OY: - for ( ; point < point_limit; point++ ) - { - point->u = point->y; - point->v = point->oy; - } - break; + point = point->next; + } - default: - for ( ; point < point_limit; point++ ) + 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->x; - point->v = point->y; + 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; } } } + /* + * + * W E A K P O I N T I N T E R P O L A T I O N + * + */ + + static void + af_iup_shift( AF_Point p1, + AF_Point p2, + AF_Point ref ) + { + AF_Point p; + FT_Pos delta = ref->u - ref->v; + + + for ( p = p1; p < ref; p++ ) + p->u = p->v + delta; + + for ( p = ref + 1; p <= p2; p++ ) + p->u = p->v + delta; + } + + + static void + af_iup_interp( AF_Point p1, + AF_Point p2, + AF_Point ref1, + AF_Point ref2 ) + { + AF_Point p; + FT_Pos u; + FT_Pos v1 = ref1->v; + FT_Pos v2 = ref2->v; + FT_Pos d1 = ref1->u - v1; + FT_Pos d2 = ref2->u - v2; + + + if ( p1 > p2 ) + return; + + if ( v1 == v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else + u += d2; + + p->u = u; + } + return; + } + + if ( v1 < v2 ) + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v1 ) + u += d1; + else if ( u >= v2 ) + u += d2; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + else + { + for ( p = p1; p <= p2; p++ ) + { + u = p->v; + + if ( u <= v2 ) + u += d2; + else if ( u >= v1 ) + u += d1; + else + u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 ); + + p->u = u; + } + } + } + + + FT_LOCAL_DEF( void ) + af_glyph_hints_align_weak_points( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_Point points = hints->points; + AF_Point point_limit = points + hints->num_points; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + AF_Flags touch_flag; + AF_Point point; + AF_Point end_point; + AF_Point first_point; + + + /* PASS 1: Move segment points to edge positions */ + + if ( dim == AF_DIMENSION_HORZ ) + { + touch_flag = AF_FLAG_TOUCH_X; + + for ( point = points; point < point_limit; point++ ) + { + point->u = point->x; + point->v = point->ox; + } + } + else + { + touch_flag = AF_FLAG_TOUCH_Y; + + for ( point = points; point < point_limit; points++ ) + { + point->u = point->y; + point->v = point->oy; + } + } + + point = points; + + for ( ; contour < contour_limit; contour++ ) + { + point = *contour; + end_point = point->prev; + first_point = point; + + while ( point <= end_point && !( point->flags & touch_flag ) ) + point++; + + if ( point <= end_point ) + { + AF_Point first_touched = point; + AF_Point cur_touched = point; + + + point++; + while ( point <= end_point ) + { + if ( point->flags & touch_flag ) + { + /* we found two successive touched points; we interpolate */ + /* all contour points between them */ + af_iup_interp( cur_touched + 1, point - 1, + cur_touched, point ); + cur_touched = point; + } + point++; + } + + if ( cur_touched == first_touched ) + { + /* this is a special case: only one point was touched in the */ + /* contour; we thus simply shift the whole contour */ + af_iup_shift( first_point, end_point, cur_touched ); + } + else + { + /* now interpolate after the last touched point to the end */ + /* of the contour */ + af_iup_interp( cur_touched + 1, end_point, + cur_touched, first_touched ); + + /* if the first contour point isn't touched, interpolate */ + /* from the contour start to the first touched point */ + if ( first_touched > points ) + af_iup_interp( first_point, first_touched - 1, + cur_touched, first_touched ); + } + } + } + + /* now save the interpolated values back to x/y */ + if ( dim == AF_DIMENSION_HORZ ) + { + for ( point = points; point < point_limit; point++ ) + point->x = point->u; + } + else + { + for ( point = points; point < point_limit; point++ ) + point->y = point->u; + } + } + + + diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h index 4d736514b..2f5f4ecf2 100644 --- 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 @@ FT_BEGIN_HEADER AF_DIMENSION_VERT = 1, /* y coordinates, i.e. horizontal segments & edges */ AF_DIMENSION_MAX /* do not remove */ - + } AF_Dimension; @@ -30,7 +30,7 @@ FT_BEGIN_HEADER AF_DIR_LEFT = -1, AF_DIR_UP = 2, AF_DIR_DOWN = -2 - + } AF_Direction; @@ -38,32 +38,32 @@ FT_BEGIN_HEADER 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 @@ FT_BEGIN_HEADER AF_EDGE_ROUND = (1 << 0), AF_EDGE_SERIF = (1 << 1), AF_EDGE_DONE = (1 << 2) - + } AF_Edge_Flags; @@ -110,10 +110,10 @@ FT_BEGIN_HEADER 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 @@ FT_BEGIN_HEADER 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 @@ FT_BEGIN_HEADER AF_Segment first; AF_Segment last; - } AF_EdgeRec; @@ -150,7 +149,7 @@ FT_BEGIN_HEADER { FT_Int num_segments; AF_Segment segments; - + FT_Int num_edges; AF_Edge edges; @@ -158,8 +157,8 @@ FT_BEGIN_HEADER } AF_AxisHintsRec, *AF_AxisHints; - - typedef struct AF_OutlineHintsRec_ + + typedef struct AF_GlyphHintsRec_ { FT_Memory memory; @@ -177,7 +176,7 @@ FT_BEGIN_HEADER AF_AxisHintsRec axis[ AF_DIMENSION_MAX ]; - } AF_OutlineHintsRec; + } AF_GlyphHintsRec; @@ -188,43 +187,36 @@ FT_BEGIN_HEADER 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 ); /* */ diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index f92f67a6a..f748b111e 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -1,8 +1,438 @@ #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; @@ -23,9 +453,28 @@ 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 */ @@ -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 @@ } - /*************************************************************************/ - /* */ - /* */ - /* af_outline_detect_features */ - /* */ - /* */ - /* 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,92 +1019,50 @@ } - /*************************************************************************/ - /* */ - /* */ - /* af_outline_compute_blue_edges */ - /* */ - /* */ - /* 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; - - FT_Bool blue_active[AF_BLUE_MAX]; + 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; /* 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 ); - - - if ( !blue_active[blue] ) - continue; + is_top_blue = (bb->flags & AF_LATIN_BLUE_TOP) != 0; + is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); /* 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 */ @@ -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 @@ } - /*************************************************************************/ - /* */ - /* */ - /* af_outline_scale_blue_edges */ - /* */ - /* */ - /* 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'). */ - /* */ - FT_LOCAL_DEF( void ) - af_outline_hints_scale_blue_edges( AF_OutlineHints hints ) outline, + static FT_Error + af_latin_hints_init( AF_GlyphHints hints, + AF_Scaler scaler, + AF_LatinMetrics metrics ) { - AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ]; - AF_Edge edge = axis->edges; - AF_Edge edge_limit = edge + axis->num_edges; - FT_Pos delta; + 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; - delta = globals->scaled.blue_refs - globals->design.blue_refs; - - for ( ; edge < edge_limit; edge++ ) + for ( n = 0; n < count; n++ ) { - if ( edge->blue_edge ) - edge->blue_edge += delta; + 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); + } + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** E D G E H I N T I N G ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_LOCAL_DEF( void ) + af_latin_hint_edges( AF_GlyphHints hints, + AF_Dimension dim ) + { + AF_AxisHints axis = & hints->axis[dim]; + AF_Edge edges = axis->edges; + AF_Edge edge_limit = edges + axis->num_edges; + FT_Int n_edges; + AF_Edge edge; + AF_Edge anchor = 0; + FT_Int has_serifs = 0; + + + /* 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; + + + 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++ ) + { + 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 + }; + diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h index 5c716e87f..816c5c5b8 100644 --- a/src/autofit/aflatin.h +++ b/src/autofit/aflatin.h @@ -11,6 +11,14 @@ FT_BEGIN_HEADER */ 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 @@ FT_BEGIN_HEADER * 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 @@ FT_BEGIN_HEADER AF_Scaler scaler ); - /* - * Latin (glyph) hints management - * + + /***************************************************************************/ + /***************************************************************************/ + /***** *****/ + /***** L A T I N G L Y P H A N A L Y S I S *****/ + /***** *****/ + /***************************************************************************/ + /***************************************************************************/ + + + /* this shouldn't normally be exported. However, other scripts might + * like to use this function as-is */ + FT_LOCAL( void ) + af_latin_hints_compute_segments( AF_GlyphHints hints, + AF_Dimension dim ); - FT_LOCAL( + /* this shouldn't normally be exported. However, other scripts might + * want to use this function as-is + */ + FT_LOCAL( void ) + 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_compute_edges( AF_GlyphHints hints, + AF_Dimension dim ); FT_LOCAL( void ) - af_latin_hints_compute_segments( AF_OutlineHints hints, - AF_Dimension dim ); - - FT_LOCAL( void ) - af_latin_hints_link_segments( AF_OutlineHints hints, - AF_Dimension dim ); - - FT_LOCAL( void ) - af_latin_hints_compute_edges( AF_OutlineHints hints, - AF_Dimension dim ); - - FT_LOCAL( void ) - af_latin_hints_init( AF_OutlineHints hints, - AF_Dimension dim ); - + af_latin_hints_detect_features( AF_GlyphHints hints, + AF_Dimension dim ); /* */ diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index a8a2b8d89..0bc9eb118 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -1,6 +1,9 @@ #ifndef __AFTYPES_H__ #define __AFTYPES_H__ +#include +#include FT_FREETYPE_H + FT_BEGIN_HEADER /**************************************************************************/ @@ -24,6 +27,27 @@ FT_BEGIN_HEADER #endif /* AF_DEBUG */ + /**************************************************************************/ + /**************************************************************************/ + /***** *****/ + /***** 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 ); + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -73,13 +97,17 @@ FT_BEGIN_HEADER /**************************************************************************/ /**************************************************************************/ - typedef struct AF_OutlineHintsRec_* AF_OutlineHints; - - typedef struct AF_GlobalHintsRec_* AF_GlobalHints; + /* opaque handle to glyph-specific hints. see "afhints.h" for more + * details + */ + typedef struct AF_GlyphHintsRec_* AF_GlyphHints; + /* 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,53 +115,10 @@ FT_BEGIN_HEADER 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,30 +175,32 @@ FT_BEGIN_HEADER * - 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 */ } 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,21 +208,23 @@ FT_BEGIN_HEADER /* 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_ { @@ -248,40 +237,19 @@ FT_BEGIN_HEADER 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; 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