[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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
diff --git a/ChangeLog b/ChangeLog
index ddc68ce..11dc4c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h
index 6e1b1ff..c0ebd0d 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 825c361..a0d9ebc 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;