From 14018b4af9c4274e0b89cd31e94ef78109f0d912 Mon Sep 17 00:00:00 2001 From: David Turner Date: Sun, 12 Jan 2003 18:26:10 +0000 Subject: [PATCH] 2003-01-11 David Chester * include/freetype/config/ftoption.h, src/autohint/ahglobal.h, src/autohint/ahglobal.c, src/autohint/ahglyph.c, src/autohint/ahtypes.h: included David Chester's patches to the auto-hinter in order to slightly improve the output. Note that everything is controlled through the new FT_CONFIG_OPTION_CHESTER_HINTS defined at the end of "ftoption.h", there are also individual FT_CONFIG_CHESTER_XXX macros to control individual "features". Note that all improvements are enabled by default, but can be tweaked for optimization and testing purpose. The configuration macros will most likely disappear in the short future. 2003-01-11 David Turner * include/freetype/internal/fnttypes.h: fixed a structure field definition to avoid memory overwrites --- ChangeLog | 21 +++ include/freetype/config/ftoption.h | 11 ++ include/freetype/internal/fnttypes.h | 2 +- src/autohint/ahglobal.c | 3 + src/autohint/ahglobal.h | 14 +- src/autohint/ahglyph.c | 18 +- src/autohint/ahhint.c | 255 +++++++++++++++++++++++++++ src/autohint/ahtypes.h | 26 ++- src/truetype/ttobjs.c | 11 ++ 9 files changed, 351 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ee3271f5..749395ed1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2003-01-11 David Chester + + * include/freetype/config/ftoption.h, src/autohint/ahglobal.h, + src/autohint/ahglobal.c, src/autohint/ahglyph.c, + src/autohint/ahtypes.h: + + included David Chester's patches to the auto-hinter in order to + slightly improve the output. Note that everything is controlled + through the new FT_CONFIG_OPTION_CHESTER_HINTS defined at the + end of "ftoption.h", there are also individual FT_CONFIG_CHESTER_XXX + macros to control individual "features". + + Note that all improvements are enabled by default, but can be + tweaked for optimization and testing purpose. The configuration + macros will most likely disappear in the short future. + +2003-01-11 David Turner + + * include/freetype/internal/fnttypes.h: fixed a structure field + definition to avoid memory overwrites + 2003-01-08 Huw Dawies * src/winfonts/winfnt.c: read 16 bytes into "reserved2", not "reserved" diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 85c9e45be..d5515c29f 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -469,6 +469,17 @@ FT_BEGIN_HEADER /* */ +#undef FT_CONFIG_OPTION_CHESTER_HINTS + +#ifdef FT_CONFIG_OPTION_CHESTER_HINTS + +# define FT_CONFIG_CHESTER_SMALL_F +# define FT_CONFIG_CHESTER_ASCENDER +# define FT_CONFIG_CHESTER_SERIF +# define FT_CONFIG_CHESTER_STEM + +#endif /* FT_CONFIG_OPTION_CHESTER_HINTS */ + FT_END_HEADER diff --git a/include/freetype/internal/fnttypes.h b/include/freetype/internal/fnttypes.h index 54e37ec4c..2edc56717 100644 --- a/include/freetype/internal/fnttypes.h +++ b/include/freetype/internal/fnttypes.h @@ -108,7 +108,7 @@ FT_BEGIN_HEADER FT_UShort B_space; FT_UShort C_space; FT_UShort color_table_offset; - FT_Byte reserved2[4]; + FT_Byte reserved2[16]; } WinFNT_HeaderRec, *WinFNT_Header; diff --git a/src/autohint/ahglobal.c b/src/autohint/ahglobal.c index 2ce8ac35c..b8fb48afd 100644 --- a/src/autohint/ahglobal.c +++ b/src/autohint/ahglobal.c @@ -32,6 +32,9 @@ { "THEZOCQS", "HEZLOCUS", +#ifdef FT_CONFIG_CHESTER_SMALL_F + "fijkdbh", +#endif "xzroesc", "xzroesc", "pqgjy" diff --git a/src/autohint/ahglobal.h b/src/autohint/ahglobal.h index 9d557b92c..ef99a01fd 100644 --- a/src/autohint/ahglobal.h +++ b/src/autohint/ahglobal.h @@ -32,8 +32,18 @@ FT_BEGIN_HEADER -#define AH_IS_TOP_BLUE( b ) ( (b) == AH_BLUE_CAPITAL_TOP || \ - (b) == AH_BLUE_SMALL_TOP ) +#ifdef FT_CONFIG_CHESTER_SMALL_F + +# define AH_IS_TOP_BLUE( b ) ( (b) == AH_BLUE_CAPITAL_TOP || \ + (b) == AH_BLUE_SMALL_F_TOP || \ + (b) == AH_BLUE_SMALL_TOP ) + +#else /* !CHESTER_SMALL_F */ + +# define AH_IS_TOP_BLUE( b ) ( (b) == AH_BLUE_CAPITAL_TOP || \ + (b) == AH_BLUE_SMALL_TOP ) + +#endif /* !CHESTER_SMALL_F */ /* compute global metrics automatically */ diff --git a/src/autohint/ahglyph.c b/src/autohint/ahglyph.c index ee628be3b..d4fcd4b31 100644 --- a/src/autohint/ahglyph.c +++ b/src/autohint/ahglyph.c @@ -1350,10 +1350,20 @@ else edge2 = seg2->edge; +#ifdef FT_CONFIG_CHESTER_SERIF + if ( is_serif ) + { + edge->serif = edge2; + edge2->flags |= AH_EDGE_SERIF; + } + else + edge->link = edge2; +#else /* !CHESTER_SERIF */ if ( is_serif ) edge->serif = edge2; else edge->link = edge2; +#endif } seg = seg->edge_next; @@ -1477,8 +1487,14 @@ /* compute the initial threshold as a fraction of the EM size */ best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_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; + best_dist = 64 / 4; +#endif for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ ) { diff --git a/src/autohint/ahhint.c b/src/autohint/ahhint.c index 1e2b7b342..e64ac7ff1 100644 --- a/src/autohint/ahhint.c +++ b/src/autohint/ahhint.c @@ -88,6 +88,137 @@ /* compute the snapped width of a given stem */ +#ifdef FT_CONFIG_CHESTER_SERIF + static FT_Pos + ah_compute_stem_width( AH_Hinter hinter, + int vertical, + FT_Pos width, + AH_Edge_Flags base_flags, + AH_Edge_Flags stem_flags ) + { + AH_Globals globals = &hinter->globals->scaled; + FT_Pos dist = width; + FT_Int sign = 0; + + + 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 & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) + goto Done_Width; + + else if ( ( base_flags & AH_EDGE_ROUND ) ) + { + if ( dist < 96 ) + 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 = ah_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 = ah_snap_width( globals->widths, globals->num_widths, dist ); + + if ( hinter->flags & AH_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, prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & -64; + } + } + } + + Done_Width: + if ( sign ) + dist = -dist; + + return dist; + } +#else /* !CHESTER_SERIF */ static FT_Pos ah_compute_stem_width( AH_Hinter hinter, int vertical, @@ -201,6 +332,7 @@ return dist; } +#endif /* !CHESTER_SERIF */ /* align one stem edge relative to the previous stem edge */ @@ -212,9 +344,18 @@ { FT_Pos dist = stem_edge->opos - base_edge->opos; +#ifdef FT_CONFIG_CHESTER_SERIF + FT_Pos fitted_width = ah_compute_stem_width( hinter, + vertical, + dist, + base_edge->flags, + stem_edge->flags ); + stem_edge->pos = base_edge->pos + fitted_width; +#else stem_edge->pos = base_edge->pos + ah_compute_stem_width( hinter, vertical, dist ); +#endif } @@ -368,12 +509,61 @@ if ( !anchor ) { +#ifdef FT_CONFIG_CHESTER_STEM + 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 = ah_compute_stem_width( hinter, dimension, 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 |= AH_EDGE_DONE; + + ah_align_linked_edge( hinter, edge, edge2, dimension ); +#else /* !CHESTER_STEM */ edge->pos = ( edge->opos + 32 ) & -64; anchor = edge; edge->flags |= AH_EDGE_DONE; ah_align_linked_edge( hinter, edge, edge2, dimension ); +#endif /* !CHESTER_STEM */ } else { @@ -385,7 +575,70 @@ org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); +#ifdef FT_CONFIG_CHESTER_SERIF + cur_len = ah_compute_stem_width( hinter, dimension, org_len, + edge->flags, edge2->flags ); +#else /* !CHESTER_SERIF */ cur_len = ah_compute_stem_width( hinter, dimension, org_len ); +#endif /* !CHESTER_SERIF */ + +#ifdef FT_CONFIG_CHESTER_STEM + 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 = ah_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; + } + +#else /* !CHESTER_STEM */ cur_pos1 = ( org_pos + 32 ) & -64; delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center ); @@ -400,6 +653,8 @@ edge->pos = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2; edge2->pos = edge->pos + cur_len; +#endif /* !CHESTER_STEM */ + edge->flags |= AH_EDGE_DONE; edge2->flags |= AH_EDGE_DONE; diff --git a/src/autohint/ahtypes.h b/src/autohint/ahtypes.h index c9fbf274d..33633b12c 100644 --- a/src/autohint/ahtypes.h +++ b/src/autohint/ahtypes.h @@ -385,12 +385,26 @@ FT_BEGIN_HEADER } AH_OutlineRec, *AH_Outline; -#define AH_BLUE_CAPITAL_TOP 0 /* THEZOCQS */ -#define AH_BLUE_CAPITAL_BOTTOM ( AH_BLUE_CAPITAL_TOP + 1 ) /* HEZLOCUS */ -#define AH_BLUE_SMALL_TOP ( AH_BLUE_CAPITAL_BOTTOM + 1 ) /* xzroesc */ -#define AH_BLUE_SMALL_BOTTOM ( AH_BLUE_SMALL_TOP + 1 ) /* xzroesc */ -#define AH_BLUE_SMALL_MINOR ( AH_BLUE_SMALL_BOTTOM + 1 ) /* pqgjy */ -#define AH_BLUE_MAX ( AH_BLUE_SMALL_MINOR + 1 ) +#ifdef FT_CONFIG_CHESTER_SMALL_F + +# define AH_BLUE_CAPITAL_TOP 0 /* THEZOCQS */ +# define AH_BLUE_CAPITAL_BOTTOM ( AH_BLUE_CAPITAL_TOP + 1 ) /* HEZLOCUS */ +# define AH_BLUE_SMALL_F_TOP ( AH_BLUE_CAPITAL_BOTTOM + 1 ) /* fijkdbh */ +# define AH_BLUE_SMALL_TOP ( AH_BLUE_SMALL_F_TOP + 1 ) /* xzroesc */ +# define AH_BLUE_SMALL_BOTTOM ( AH_BLUE_SMALL_TOP + 1 ) /* xzroesc */ +# define AH_BLUE_SMALL_MINOR ( AH_BLUE_SMALL_BOTTOM + 1 ) /* pqgjy */ +# define AH_BLUE_MAX ( AH_BLUE_SMALL_MINOR + 1 ) + +#else /* !CHESTER_SMALL_F */ + +# define AH_BLUE_CAPITAL_TOP 0 /* THEZOCQS */ +# define AH_BLUE_CAPITAL_BOTTOM ( AH_BLUE_CAPITAL_TOP + 1 ) /* HEZLOCUS */ +# define AH_BLUE_SMALL_TOP ( AH_BLUE_CAPITAL_BOTTOM + 1) /* xzroesc */ +# define AH_BLUE_SMALL_BOTTOM ( AH_BLUE_SMALL_TOP + 1 ) /* xzroesc */ +# define AH_BLUE_SMALL_MINOR ( AH_BLUE_SMALL_BOTTOM + 1 ) /* pqgjy */ +# define AH_BLUE_MAX ( AH_BLUE_SMALL_MINOR + 1 ) + +#endif /* !CHESTER_SMALL_F */ typedef FT_Int AH_Blue; diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index 636d32fa4..41afa35cf 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -566,16 +566,27 @@ size->ttmetrics.y_ratio = 0x10000L; } +#ifdef FT_CONFIG_CHESTER_ASCENDER + + /* Compute root ascender, descender, test height, and max_advance */ + metrics->ascender = ( FT_MulFix( face->root.ascender, + metrics->y_scale ) + 63 ) & -64; + metrics->descender = ( FT_MulFix( face->root.descender, + metrics->y_scale ) + 0 ) & -64; +#else /* !CHESTER_ASCENDER */ /* Compute root ascender, descender, test height, and max_advance */ metrics->ascender = ( FT_MulFix( face->root.ascender, metrics->y_scale ) + 32 ) & -64; metrics->descender = ( FT_MulFix( face->root.descender, metrics->y_scale ) + 32 ) & -64; +#endif /* !CHESTER_ASCENDER */ + metrics->height = ( FT_MulFix( face->root.height, metrics->y_scale ) + 32 ) & -64; metrics->max_advance = ( FT_MulFix( face->root.max_advance_width, metrics->x_scale ) + 32 ) & -64; + #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* set to `invalid' by default */ size->strike_index = 0xFFFFU;