Commit 05c1421f8d1d0db83819be975c5a149ae41885da

Werner Lemberg 2013-07-19T23:11:23

[autofit] Fix segment classification for blue zones. The old code (essentially unchanged since the very beginning) incorrectly handled this configuration x -o- x / \ / \ / \ o o as flat and this o o / / x| x| | | o---------------o as round. (`o' and `x' are on and off points, respectively). This is a major change which should improve the rendering results enormously for many TrueType fonts, especially in the range approx. 20-40ppem, fixing the appearance of many overshoots. * src/autofit/aflatin.c (af_latin_metrics_init_blues): Look at the first and last points of the segment, not the points right before and after.

diff --git a/ChangeLog b/ChangeLog
index f525b2d..592ffca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,35 @@
-2013-07-18  Behdad Esfahbod  <behdad@google.com>
+2013-07-19  Werner Lemberg  <wl@gnu.org>
+
+	[autofit] Fix segment classification for blue zones.
+
+	The old code (essentially unchanged since the very beginning)
+	incorrectly handled this configuration
+
+	               x -o- x
+	                /   \
+	               /     \
+	              /       \
+	             o         o
+
+	as flat and this
+
+	                o               o
+	               /               /
+	             x|              x|
+	              |               |
+	              o---------------o
+
+	as round.  (`o' and `x' are on and off points, respectively). 
+
+	This is a major change which should improve the rendering results
+	enormously for many TrueType fonts, especially in the range approx. 
+	20-40ppem, fixing the appearance of many overshoots.
+
+	* src/autofit/aflatin.c (af_latin_metrics_init_blues): Look at the
+	first and last points of the segment, not the points right before
+	and after.
+
+2013-07-19  Behdad Esfahbod  <behdad@google.com>
 
 	[sfnt] `sbix' fix-ups.
 
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index a5d80c1..ec54b70 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -328,10 +328,14 @@
         {
           FT_Pos  best_x = points[best_point].x;
           FT_Int  prev, next;
+          FT_Int  best_segment_first, best_segment_last;
           FT_Int  best_on_point_first, best_on_point_last;
           FT_Pos  dist;
 
 
+          best_segment_first = best_point;
+          best_segment_last  = best_point;
+
           if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
           {
             best_on_point_first = best_point;
@@ -343,8 +347,9 @@
             best_on_point_last  = -1;
           }
 
-          /* look for the previous and next points that are not on the */
-          /* same Y coordinate, then threshold the `closeness'...      */
+          /* look for the previous and next points on the contour  */
+          /* that are not on the same Y coordinate, then threshold */
+          /* the `closeness'...                                    */
           prev = best_point;
           next = prev;
 
@@ -362,6 +367,8 @@
               if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
                 break;
 
+            best_segment_first = prev;
+
             if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
             {
               best_on_point_first = prev;
@@ -383,6 +390,8 @@
               if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
                 break;
 
+            best_segment_last = next;
+
             if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
             {
               best_on_point_last = next;
@@ -392,8 +401,14 @@
 
           } while ( next != best_point );
 
-          /* now set the `round' flag depending on the segment's kind */
-          /* (value 8 is heuristic)                                   */
+          /* now set the `round' flag depending on the segment's kind: */
+          /*                                                           */
+          /* - if the horizontal distance between the first and last   */
+          /*   `on' point is larger than upem/8 (value 8 is heuristic) */
+          /*   we have a flat segment                                  */
+          /* - if either the first or the last point of the segment is */
+          /*   an `off' point, the segment is round, otherwise it is   */
+          /*   flat                                                    */
           if ( best_on_point_first >= 0                               &&
                best_on_point_last >= 0                                &&
                (FT_UInt)( FT_ABS( points[best_on_point_last].x -
@@ -402,8 +417,10 @@
             round = 0;
           else
             round = FT_BOOL(
-              FT_CURVE_TAG( outline.tags[prev] ) != FT_CURVE_TAG_ON ||
-              FT_CURVE_TAG( outline.tags[next] ) != FT_CURVE_TAG_ON );
+                      FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
+                        FT_CURVE_TAG_ON                                   ||
+                      FT_CURVE_TAG( outline.tags[best_segment_last]  ) !=
+                        FT_CURVE_TAG_ON                                   );
 
           FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
         }