From 63bef9a588c3410007ead16e4121830cc1b1b2e2 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Thu, 1 May 2014 07:16:05 +0200 Subject: [PATCH] [autofit] Fix handling of neutral blue zones in stems. * src/autofit/afhints.h (AF_Edge_Flags): New value `AF_EDGE_NEUTRAL'. * src/autofit/aflatin.c (af_latin_hints_compute_blue_edges): Trace neutral blue zones with AF_EDGE_NEUTRAL. (af_latin_hint_edges): Skip neutral blue zones if necessary. --- ChangeLog | 11 +++++++ src/autofit/afhints.h | 9 +++--- src/autofit/aflatin.c | 71 ++++++++++++++++++++++++++++++++----------- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index ddc68cee2..11dc4c2d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2014-05-01 Werner Lemberg + + [autofit] Fix handling of neutral blue zones in stems. + + * src/autofit/afhints.h (AF_Edge_Flags): New value + `AF_EDGE_NEUTRAL'. + + * src/autofit/aflatin.c (af_latin_hints_compute_blue_edges): Trace + neutral blue zones with AF_EDGE_NEUTRAL. + (af_latin_hint_edges): Skip neutral blue zones if necessary. + 2014-04-28 Werner Lemberg [autofit] Introduce neutral blue zones to the latin module. diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h index 6e1b1ff99..c0ebd0d0b 100644 --- a/src/autofit/afhints.h +++ b/src/autofit/afhints.h @@ -244,10 +244,11 @@ FT_BEGIN_HEADER /* edge hint flags */ typedef enum AF_Edge_Flags_ { - AF_EDGE_NORMAL = 0, - AF_EDGE_ROUND = 1 << 0, - AF_EDGE_SERIF = 1 << 1, - AF_EDGE_DONE = 1 << 2 + AF_EDGE_NORMAL = 0, + AF_EDGE_ROUND = 1 << 0, + AF_EDGE_SERIF = 1 << 1, + AF_EDGE_DONE = 1 << 2, + AF_EDGE_NEUTRAL = 1 << 3 /* set if edge aligns to a neutral blue zone */ } AF_Edge_Flags; diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 825c3612e..a0d9ebc7d 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -1841,8 +1841,9 @@ for ( ; edge < edge_limit; edge++ ) { FT_UInt bb; - AF_Width best_blue = NULL; - FT_Pos best_dist; /* initial threshold */ + AF_Width best_blue = NULL; + FT_Bool best_blue_is_neutral = 0; + FT_Pos best_dist; /* initial threshold */ /* compute the initial threshold as a fraction of the EM size */ @@ -1856,7 +1857,7 @@ for ( bb = 0; bb < latin->blue_count; bb++ ) { AF_LatinBlue blue = latin->blues + bb; - FT_Bool is_top_blue, is_major_dir; + FT_Bool is_top_blue, is_neutral_blue, is_major_dir; /* skip inactive blue zones (i.e., those that are too large) */ @@ -1867,12 +1868,15 @@ /* direction); if it is a bottom zone, check for left edges (in */ /* the major direction) -- this assumes the TrueType convention */ /* for the orientation of contours */ - is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); - is_major_dir = FT_BOOL( edge->dir == axis->major_dir ); + is_top_blue = + (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 ); + is_neutral_blue = + (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0); + is_major_dir = + FT_BOOL( edge->dir == axis->major_dir ); /* neutral blue zones are handled for both directions */ - if ( is_top_blue ^ is_major_dir || - blue->flags & AF_LATIN_BLUE_NEUTRAL ) + if ( is_top_blue ^ is_major_dir || is_neutral_blue ) { FT_Pos dist; @@ -1885,8 +1889,9 @@ dist = FT_MulFix( dist, scale ); if ( dist < best_dist ) { - best_dist = dist; - best_blue = &blue->ref; + best_dist = dist; + best_blue = &blue->ref; + best_blue_is_neutral = is_neutral_blue; } /* now compare it to the overshoot position and check whether */ @@ -1894,9 +1899,9 @@ /* reference position of a top zone, or under the reference */ /* position of a bottom zone (provided we don't have a */ /* neutral blue zone) */ - if ( edge->flags & AF_EDGE_ROUND && - dist != 0 && - !( blue->flags & AF_LATIN_BLUE_NEUTRAL ) ) + if ( edge->flags & AF_EDGE_ROUND && + dist != 0 && + !is_neutral_blue ) { FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); @@ -1910,8 +1915,9 @@ dist = FT_MulFix( dist, scale ); if ( dist < best_dist ) { - best_dist = dist; - best_blue = &blue->shoot; + best_dist = dist; + best_blue = &blue->shoot; + best_blue_is_neutral = is_neutral_blue; } } } @@ -1919,7 +1925,11 @@ } if ( best_blue ) + { edge->blue_edge = best_blue; + if ( best_blue_is_neutral ) + edge->flags |= AF_EDGE_NEUTRAL; + } } } @@ -2304,14 +2314,41 @@ if ( edge->flags & AF_EDGE_DONE ) continue; - blue = edge->blue_edge; edge1 = NULL; edge2 = edge->link; + /* + * If a stem contains both a neutral and a non-neutral blue zone, + * skip the neutral one. Otherwise, outlines with different + * directions might be incorrectly aligned at the same vertical + * position. + * + * If we have two neutral blue zones, skip one of them. + * + */ + if ( edge->blue_edge && edge2 && edge2->blue_edge ) + { + FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL; + FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL; + + + if ( ( neutral && neutral2 ) || neutral2 ) + { + edge2->blue_edge = NULL; + edge2->flags &= ~AF_EDGE_NEUTRAL; + } + else if ( neutral ) + { + edge->blue_edge = NULL; + edge->flags &= ~AF_EDGE_NEUTRAL; + } + } + + blue = edge->blue_edge; if ( blue ) edge1 = edge; - /* flip edges if the other stem is aligned to a blue zone */ + /* flip edges if the other edge is aligned to a blue zone */ else if ( edge2 && edge2->blue_edge ) { blue = edge2->blue_edge; @@ -2378,7 +2415,7 @@ /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { - FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2-edges )); + FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges )); af_latin_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE;