Commit 5e353f07865a5ffbc141fe26cd377469693bcdcd

Werner Lemberg 2016-07-04T14:59:22

[autofit] Handle single-point contours as segments. Doing so allows us to link them to edges – some fonts like `NotoSansGurmukhi-Regular' have such isolated points sitting exactly on other outlines. * src/autofit/aflatin.c (af_latin_hints_compute_segments): Don't ignore one-point contours but handle them specially as one-point segments. (af_latin_hints_compute_edges): Append one-point segments to edges if possible.

diff --git a/ChangeLog b/ChangeLog
index 94d875b..0fb1465 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2016-07-04  Werner Lemberg  <wl@gnu.org>
+
+	[autofit] Handle single-point contours as segments.
+
+	Doing so allows us to link them to edges – some fonts like
+	`NotoSansGurmukhi-Regular' have such isolated points sitting exactly
+	on other outlines.
+
+	* src/autofit/aflatin.c (af_latin_hints_compute_segments): Don't
+	ignore one-point contours but handle them specially as one-point
+	segments.
+	(af_latin_hints_compute_edges): Append one-point segments to edges
+	if possible.
+
 2016-07-02  Werner Lemberg  <wl@gnu.org>
 
 	[autofit] Remove unused structure members.
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index f9b8507..7ccf3f6 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -1466,9 +1466,6 @@
       FT_Pos     prev_max_on_coord = max_on_coord;
 
 
-      if ( point == last )  /* skip singletons -- just in case */
-        continue;
-
       if ( FT_ABS( last->out_dir )  == major_dir &&
            FT_ABS( point->out_dir ) == major_dir )
       {
@@ -1685,7 +1682,12 @@
           passed = 1;
         }
 
-        if ( !on_edge && FT_ABS( point->out_dir ) == major_dir )
+        /* if we are not on an edge, check whether the major direction */
+        /* coincides with the current point's `out' direction, or      */
+        /* whether we have a single-point contour                      */
+        if ( !on_edge                                  &&
+             ( FT_ABS( point->out_dir ) == major_dir ||
+               point == point->prev                  ) )
         {
           /* this is the start of a new segment! */
           segment_dir = (AF_Direction)point->out_dir;
@@ -1719,6 +1721,24 @@
             min_on_coord = max_on_coord = point->v;
 
           on_edge = 1;
+
+          if ( point == point->prev )
+          {
+            /* we have a one-point segment: this is a one-point */
+            /* contour with `in' and `out' direction set to     */
+            /* AF_DIR_NONE                                      */
+            segment->pos = (FT_Short)min_pos;
+
+            if (point->flags & AF_FLAG_CONTROL)
+              segment->flags |= AF_EDGE_ROUND;
+
+            segment->min_coord = (FT_Short)point->v;
+            segment->max_coord = (FT_Short)point->v;
+            segment->height = 0;
+
+            on_edge = 0;
+            segment = NULL;
+          }
         }
 
         point = point->next;
@@ -2002,7 +2022,10 @@
       FT_Int   ee;
 
 
-      if ( seg->height < segment_length_threshold )
+      /* ignore too short segments and, in this loop, */
+      /* one-point segments without a direction       */
+      if ( seg->height < segment_length_threshold ||
+           seg->dir == AF_DIR_NONE                )
         continue;
 
       /* A special case for serif edges: If they are smaller than */
@@ -2064,6 +2087,44 @@
       }
     }
 
+    /* we loop again over all segments to catch one-point segments   */
+    /* without a direction: if possible, link them to existing edges */
+    for ( seg = segments; seg < segment_limit; seg++ )
+    {
+      AF_Edge  found = NULL;
+      FT_Int   ee;
+
+
+      if ( seg->dir != AF_DIR_NONE )
+        continue;
+
+      /* look for an edge corresponding to the segment */
+      for ( ee = 0; ee < axis->num_edges; ee++ )
+      {
+        AF_Edge  edge = axis->edges + ee;
+        FT_Pos   dist;
+
+
+        dist = seg->pos - edge->fpos;
+        if ( dist < 0 )
+          dist = -dist;
+
+        if ( dist < edge_distance_threshold )
+        {
+          found = edge;
+          break;
+        }
+      }
+
+      /* one-point segments without a match are ignored */
+      if ( found )
+      {
+        seg->edge_next         = found->first;
+        found->last->edge_next = seg;
+        found->last            = seg;
+      }
+    }
+
 
     /******************************************************************/
     /*                                                                */