[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.
This commit is contained in:
Werner Lemberg 2014-05-01 07:16:05 +02:00
parent ccfc4b4c4e
commit 63bef9a588
3 changed files with 70 additions and 21 deletions

View File

@ -1,3 +1,14 @@
2014-05-01 Werner Lemberg <wl@gnu.org>
[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 <wl@gnu.org>
[autofit] Introduce neutral blue zones to the latin module.

View File

@ -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;

View File

@ -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;