diff --git a/ChangeLog b/ChangeLog index 4c3cab8e3..68baf19f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2016-03-05 Werner Lemberg + + [autofit] Avoid excessive stem length rounding (#25392). + + * src/autofit/aflatin.c (af_latin_compute_stem_width): Add argument + to pass difference between hinted and unhinted position of base + point; use this to adjust the stem width depending on the PPEM so + that it doesn't become too large under certain circumstances. + Update all callers using value 0 for this argument except... + (af_latin_align_linked_edge): Pass position delta of base point to + `af_latin_compute_stem_width'. + 2016-03-05 J Raynor Make FreeType compile on AIX out of the box. diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index e9fb9dffe..dddfadab0 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -2504,12 +2504,14 @@ af_latin_compute_stem_width( AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, + FT_Pos base_delta, FT_UInt base_flags, FT_UInt stem_flags ) { AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos dist = width; + FT_Pos bdelta = 0; FT_Int sign = 0; FT_Int vertical = ( dim == AF_DIMENSION_VERT ); @@ -2524,6 +2526,32 @@ sign = 1; } + /* A stem's end position depends on two values: the start position */ + /* and the stem length. The former gets usually rounded to the grid, */ + /* while the latter gets rounded also if it exceeds a certain length */ + /* (see below in this function). This `double rounding' can lead to */ + /* a great difference to the original, unhinted position; this */ + /* normally doesn't matter for large PPEM values, but for small sizes */ + /* it can easily make outlines collide. For this reason, we adjust */ + /* the stem length by a small amount depending on the PPEM value in */ + /* case the former and latter rounding both point into the same */ + /* direction. */ + + if ( ( ( width > 0 ) && ( base_delta > 0 ) ) || + ( ( width < 0 ) && ( base_delta < 0 ) ) ) + { + FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem; + + + if ( ppem < 10 ) + bdelta = base_delta; + else if ( ppem < 30 ) + bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20; + + if ( bdelta < 0 ) + bdelta = -bdelta; + } + if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) { @@ -2581,7 +2609,7 @@ dist += delta; } else - dist = ( dist + 32 ) & ~63; + dist = ( dist - bdelta + 32 ) & ~63; } } else @@ -2670,11 +2698,17 @@ AF_Edge base_edge, AF_Edge stem_edge ) { - FT_Pos dist = stem_edge->opos - base_edge->opos; + FT_Pos dist, base_delta; + FT_Pos fitted_width; - FT_Pos fitted_width = af_latin_compute_stem_width( hints, dim, dist, - base_edge->flags, - stem_edge->flags ); + + dist = stem_edge->opos - base_edge->opos; + base_delta = base_edge->pos - base_edge->opos; + + fitted_width = af_latin_compute_stem_width( hints, dim, + dist, base_delta, + base_edge->flags, + stem_edge->flags ); stem_edge->pos = base_edge->pos + fitted_width; @@ -2878,7 +2912,8 @@ org_len = edge2->opos - edge->opos; - cur_len = af_latin_compute_stem_width( hints, dim, org_len, + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, edge->flags, edge2->flags ); @@ -2947,7 +2982,8 @@ org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); - cur_len = af_latin_compute_stem_width( hints, dim, org_len, + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, edge->flags, edge2->flags ); @@ -3007,7 +3043,8 @@ org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); - cur_len = af_latin_compute_stem_width( hints, dim, org_len, + cur_len = af_latin_compute_stem_width( hints, dim, + org_len, 0, edge->flags, edge2->flags );