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;