Commit 81e725f5133557bcfafa1ec55fe6cebb9c559902

David Turner 2006-11-23T14:49:48

* src/autofit/afhints.c, src/autofit/afhints.h, src/autofit/aflatin.c, src/autofit/aftypes.h: Misc. auto-hinter improvements

diff --git a/ChangeLog b/ChangeLog
index 17b8329..18bf6a6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2006-11-23  David Turner    <david@freetype.org>
+
+	* src/autofit/afhints.c, src/autofit/afhints.h, src/autofit/aflatin.c,
+	src/autofit/aftypes.h: Misc. auto-hinter improvements
+
 2006-11-22  Werner Lemberg  <wl@gnu.org>
 
 	Fix Savannah bug #15553.
@@ -9,7 +14,7 @@
 2006-11-18  Werner Lemberg  <wl@gnu.org>
 
 	Because FT_Load_Glyph expects CID values for CID-keyed fonts, the
-	test for a valid glyph index must be deferred to the font drivers. 
+	test for a valid glyph index must be deferred to the font drivers.
 	This patch fixes Savannah bug #18301.
 
 	* src/base/ftobjs.c (FT_Load_Glyph): Don't check `glyph_index'.
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index 94692f5..7335a00 100644
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -206,19 +206,18 @@
       printf ( "Table of %s segments:\n",
                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
       printf ( "  [ index |  pos |  dir  | link | serif |"
-               " numl | first | start ]\n" );
+               " height  | extra ]\n" );
 
       for ( seg = segments; seg < limit; seg++ )
       {
-        printf ( "  [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
+        printf ( "  [ %5d | %4d | %5s | %4d | %5d | %5d | %5d ]\n",
                  seg - segments,
                  (int)seg->pos,
                  af_dir_str( seg->dir ),
                  AF_INDEX_NUM( seg->link, segments ),
                  AF_INDEX_NUM( seg->serif, segments ),
-                 (int)seg->num_linked,
-                 seg->first - points,
-                 seg->last - points );
+                 seg->height,
+                 seg->height - (seg->max_coord - seg->min_coord) );
       }
       printf( "\n" );
     }
diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h
index b6d8896..3bde12f 100644
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -125,6 +125,7 @@ FT_BEGIN_HEADER
     FT_Short    pos;         /* position of segment                 */
     FT_Short    min_coord;   /* minimum coordinate of segment       */
     FT_Short    max_coord;   /* maximum coordinate of segment       */
+    FT_Short    height;
 
     AF_Edge     edge;        /* the segment's parent edge           */
     AF_Segment  edge_next;   /* link to next segment in parent edge */
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index b6d859f..91391fc 100644
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -471,7 +471,7 @@
       if ( blue )
       {
         FT_Pos  scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
-        FT_Pos  fitted = FT_PIX_ROUND( scaled );
+        FT_Pos  fitted = (scaled + 40) & ~63;
 
 
         if ( scaled != fitted )
@@ -723,6 +723,7 @@
 
             segment->min_coord = (FT_Short)min_pos;
             segment->max_coord = (FT_Short)max_pos;
+            segment->height    = segment->max_coord - segment->min_coord;
 
             on_edge = 0;
             segment = NULL;
@@ -770,6 +771,51 @@
 
     } /* contours */
 
+
+   /* now slightly increase the height of segments when this makes sense
+    * this is used to better detect and ignore serifs
+    */
+    {
+      AF_Segment  segments      = axis->segments;
+      AF_Segment  segments_end = segments + axis->num_segments;
+
+      for ( segment = segments; segment < segments_end; segment++ )
+      {
+        AF_Point  first = segment->first;
+        AF_Point  last  = segment->last;
+        FT_Pos    first_v = first->v;
+        FT_Pos    last_v  = last->v;
+
+        if ( first == last )
+          continue;
+
+        if ( first_v < last_v )
+        {
+          AF_Point  p;
+
+          p = first->prev;
+          if ( p->v < first_v )
+            segment->height += (first_v - p->v) >> 1;
+
+          p = last->next;
+          if ( p->v > last_v )
+            segment->height += (p->v - last_v) >> 1;
+        }
+        else
+        {
+          AF_Point  p;
+
+          p = first->prev;
+          if ( p->v > first_v )
+            segment->height += (p->v - first_v) >> 1;
+
+          p = last->next;
+          if ( p->v < last_v )
+            segment->height += (last_v - p->v) >> 1;
+        }
+      }
+    }
+
 #ifdef AF_HINT_METRICS
     /* we need to ensure that there are edges on the left-most and  */
     /* right-most points of the glyph in order to hint the metrics; */
@@ -862,7 +908,7 @@
     if ( len_threshold == 0 )
       len_threshold = 1;
 
-    len_score = AF_LATIN_CONSTANT( hints->metrics, 3000 );
+    len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
 
     /* now compare each segment to the others */
     for ( seg1 = segments; seg1 < segment_limit; seg1++ )
@@ -961,12 +1007,12 @@
                                           : AF_DIR_RIGHT;
 
     /*
-     *  We ignore all segments that are less than 1.5 pixels in length,
+     *  We ignore all segments that are less than 1 pixels in length,
      *  to avoid many problems with serif fonts.  We compute the
      *  corresponding threshold in font units.
      */
     if ( dim == AF_DIMENSION_HORZ )
-        segment_length_threshold = FT_DivFix( 64, hints->y_scale );
+        segment_length_threshold = FT_DivFix( 96, hints->y_scale );
     else
         segment_length_threshold = 0;
 
@@ -1000,7 +1046,7 @@
       FT_Int   ee;
 
 
-      if ( seg->max_coord - seg->min_coord < segment_length_threshold )
+      if ( seg->height < segment_length_threshold )
         continue;
 
       /* look for an edge corresponding to the segment */
@@ -1742,7 +1788,7 @@
       /* now align the stem */
 
       /* this should not happen, but it's better to be safe */
-      if ( edge2->blue_edge || edge2 < edge )
+      if ( edge2->blue_edge )
       {
         AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
 
@@ -1790,14 +1836,14 @@
             cur_pos1 += d_off;
 
           edge->pos  = cur_pos1 - cur_len / 2;
-          edge2->pos = cur_pos1 + cur_len / 2;
-
+          edge2->pos = edge->pos + cur_len;
         }
         else
           edge->pos = FT_PIX_ROUND( edge->opos );
 
-        AF_LOG(( "ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
-                 edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+        AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) snapped to (%.2f) (%.2f)\n",
+                 edge-edges, edge->opos / 64., edge2-edges, edge2->opos/64.,
+                 edge->pos / 64., edge2->pos / 64. ));
         anchor = edge;
 
         edge->flags |= AF_EDGE_DONE;
@@ -1859,7 +1905,6 @@
                    edge2-edges, edge2->opos / 64.0,
                    edge->pos / 64.0, edge2->pos / 64.0 ));
         }
-
         else
         {
           org_pos    = anchor->pos + ( edge->opos - anchor->opos );
@@ -1973,20 +2018,58 @@
        */
       for ( edge = edges; edge < edge_limit; edge++ )
       {
+        FT_Pos  delta;
+
         if ( edge->flags & AF_EDGE_DONE )
           continue;
 
+        delta = 1000;
         if ( edge->serif )
+        {
+          delta = edge->serif->opos - edge->opos;
+          if ( delta < 0 )
+            delta = -delta;
+        }
+
+        if ( delta < 64+16 )
+        {
           af_latin_align_serif_edge( hints, edge->serif, edge );
+          AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) aligned to (%.2f)\n", edge-edges,
+                   edge->opos/64., edge->serif - edges, edge->serif->opos/64., edge->pos/64.0 ));
+        }
         else if ( !anchor )
         {
+          AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
+                   edge-edges, edge->opos/64., edge->pos/64. ));
           edge->pos = FT_PIX_ROUND( edge->opos );
           anchor    = edge;
         }
         else
-          edge->pos = anchor->pos +
-                      FT_PIX_ROUND( edge->opos - anchor->opos );
+        {
+          AF_Edge   before, after;
+
+          for ( before = edge-1; before >= edges; before-- )
+            if ( before->flags & AF_EDGE_DONE )
+                break;
+
+          for ( after = edge+1; after < edge_limit; after++ )
+            if ( after->flags & AF_EDGE_DONE )
+                break;
 
+          if ( before >= edges && before < edge &&
+               after  < edge_limit && after > edge )
+          {
+              edge->pos = before->pos + FT_MulDiv( edge->opos - before->opos,
+                                                   after->pos - before->pos,
+                                                   after->opos - before->opos );
+          }
+          else
+              edge->pos = anchor->pos +
+                          FT_PIX_ROUND( edge->opos - anchor->opos );
+
+          AF_LOG(( "SERIF_LINK: edge %d (opos=%.2f) snapped to (%.2f)\n",
+                   edge-edges, edge->opos/64., edge->pos/64. ));
+        }
         edge->flags |= AF_EDGE_DONE;
 
         if ( edge > edges && edge->pos < edge[-1].pos )
diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h
index d1459a4..a94c7ee 100644
--- a/src/autofit/aftypes.h
+++ b/src/autofit/aftypes.h
@@ -54,7 +54,7 @@ FT_BEGIN_HEADER
   /*************************************************************************/
 
 #define xxAF_USE_WARPER  /* only define to use warp hinting */
-#define AF_DEBUG
+#define xxAF_DEBUG
 
 #ifdef AF_DEBUG