Commit 66456162afdeef73a7a705f4e94c6ae32f71ebfd

David Turner 2002-08-21T21:34:59

* src/pshinter/pshalgo3.c, src/autohint/ahangles.c, src/autohint/ahangles.h, src/autohint/ahglyph.c, src/autohint/ahhint.c, src/autohint/ahtypes.h: the automatic and Postscript hinter now automatically detect inflection points in glyph outlines and treats them specially. This is very useful to prevent nasty effect like the disappearing diagonals of "S" and "s" in many, many fonts..

diff --git a/src/autohint/ahangles.c b/src/autohint/ahangles.c
index 1a13b27..a4ef842 100644
--- a/src/autohint/ahangles.c
+++ b/src/autohint/ahangles.c
@@ -127,4 +127,20 @@
   }
 
 
+  FT_LOCAL_DEF( AH_Angle )
+  ah_angle_diff( AH_Angle  angle1,
+                 AH_Angle  angle2 )
+  {
+    AH_Angle  delta;
+    
+    delta = ( angle2 - angle1 );
+    if ( delta < 0 )
+      delta += AH_2PI;
+    
+    if ( delta > AH_PI )
+      delta -= AH_2PI;
+    
+    return delta;
+  }                 
+
 /* END */
diff --git a/src/autohint/ahangles.h b/src/autohint/ahangles.h
index d509e00..f46bfaa 100644
--- a/src/autohint/ahangles.h
+++ b/src/autohint/ahangles.h
@@ -51,6 +51,11 @@ FT_BEGIN_HEADER
   ah_angle( FT_Vector*  v );
 
 
+  FT_LOCAL( AH_Angle )
+  ah_angle_diff( AH_Angle  angle1,
+                 AH_Angle  angle2 );
+
+
 FT_END_HEADER
 
 #endif /* __AHANGLES_H__ */
diff --git a/src/autohint/ahglyph.c b/src/autohint/ahglyph.c
index 2f0582e..8939b74 100644
--- a/src/autohint/ahglyph.c
+++ b/src/autohint/ahglyph.c
@@ -674,6 +674,120 @@
     }
   }
 
+ /* compute all inflex points in a given glyph */
+  static void
+  ah_outline_compute_inflections( AH_Outline*  outline )
+  {
+    AH_Point**   contour       =  outline->contours;
+    AH_Point**   contour_limit =  contour + outline->num_contours;
+
+    /* load original coordinates in (u,v) */
+    ah_setup_uv( outline, ah_uv_fxy );
+
+    /* do each contour separately */
+    for ( ; contour < contour_limit; contour++ )
+    {
+      FT_Vector  vec;
+      AH_Point*  point   = contour[0];
+      AH_Point*  first   = point;
+      AH_Point*  start   = point;
+      AH_Point*  end     = point;
+      AH_Point*  before;
+      AH_Point*  after;
+      AH_Angle   angle_in, angle_seg, angle_out;
+      AH_Angle   diff_in, diff_out;
+      FT_Int     finished = 0;
+
+      /* compute first segment in contour */
+      first  = point;
+
+      start = end = first;
+      do
+      {
+        end = end->next;
+        if ( end == first )
+          goto Skip;
+      }
+      while ( end->u == first->u && end->v == first->v );
+
+      vec.x = end->u - start->u;
+      vec.y = end->v - start->v;
+      angle_seg = ah_angle( &vec );
+
+      /* extend the segment start whenever possible */
+      before = start;
+      do
+      {
+        do
+        {
+          start  = before;
+          before = before->prev;
+          if ( before == first )
+            goto Skip;
+        }
+        while ( before->u == start->u && before->v == start->v );
+
+        vec.x    = start->u - before->u;
+        vec.y    = start->v - before->v;
+        angle_in = ah_angle( &vec );
+      }
+      while ( angle_in == angle_seg );
+
+      first   = start;
+      diff_in = ah_angle_diff( angle_in, angle_seg );
+
+      /* now, process all segments in the contour */
+      do
+      {
+        /* first, extend current segment's end whenever possible */
+        after = end;
+        do
+        {
+          do
+          {
+            end   = after;
+            after = after->next;
+            if ( after == first )
+              finished = 1;
+          }
+          while ( end->u == after->u && end->v == after->v );
+
+          vec.x     = after->u - end->u;
+          vec.y     = after->v - end->v;
+          angle_out = ah_angle( &vec );
+        }
+        while ( angle_out == angle_seg );
+
+        diff_out = ah_angle_diff( angle_seg, angle_out );
+
+        if ( diff_in ^ diff_out < 0 )
+        {
+          /* diff_in and diff_out have different signs, we have */
+          /* inflection points here...                          */
+
+          do
+          {
+            start->flags |= ah_flag_inflection;
+            start = start->next;
+          }
+          while ( start != end );
+
+          start->flags |= ah_flag_inflection;
+        }
+
+        start     = end;
+        end       = after;
+        angle_seg = angle_out;
+        diff_in   = diff_out;
+      }
+      while ( !finished );
+
+    Skip:
+      ;
+    }
+  }
+
+
 
   FT_LOCAL_DEF( void )
   ah_outline_compute_segments( AH_Outline*  outline )
@@ -1290,6 +1404,7 @@
     ah_outline_compute_segments( outline );
     ah_outline_link_segments   ( outline );
     ah_outline_compute_edges   ( outline );
+    ah_outline_compute_inflections( outline );
   }
 
 
diff --git a/src/autohint/ahhint.c b/src/autohint/ahhint.c
index 243b4d0..0aa5f2e 100644
--- a/src/autohint/ahhint.c
+++ b/src/autohint/ahhint.c
@@ -612,7 +612,8 @@
 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
           /* if this point is candidate to weak interpolation, we will  */
           /* interpolate it after all strong points have been processed */
-          if ( point->flags & ah_flag_weak_interpolation )
+          if (  (point->flags & ah_flag_weak_interpolation) &&
+               !(point->flags & ah_flag_inflection)         )
             continue;
 #endif
 
diff --git a/src/autohint/ahtypes.h b/src/autohint/ahtypes.h
index cd62101..4c91655 100644
--- a/src/autohint/ahtypes.h
+++ b/src/autohint/ahtypes.h
@@ -147,6 +147,7 @@ FT_BEGIN_HEADER
 
   /* weak interpolation */
 #define ah_flag_weak_interpolation  256
+#define ah_flag_inflection          512
 
   typedef FT_Int AH_Flags;
 
diff --git a/src/pshinter/pshalgo3.c b/src/pshinter/pshalgo3.c
index ccf5bc2..18ea48d 100644
--- a/src/pshinter/pshalgo3.c
+++ b/src/pshinter/pshalgo3.c
@@ -1422,7 +1422,8 @@
                point->dir_in != point->dir_out )
             continue;
 
-          if ( !psh3_point_is_extremum( point ) )
+          if ( !psh3_point_is_extremum( point )   &&
+               !psh3_point_is_inflection( point ) )
             continue;
 
           point->flags &= ~PSH3_POINT_SMOOTH;