Commit a0172d10e816fdd7b8d7b748f570ba16d9e753bd

Alexei Podtelezhnikov 2015-08-17T22:58:59

[base] Improve emboldener (#45596). * src/base/ftoutln.c (FT_Outline_EmboldenXY): Correct displacement of zero-lenght segments.

diff --git a/ChangeLog b/ChangeLog
index cf9ad5d..b3c0fd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-08-17  Alexei Podtelezhnikov  <apodtele@gmail.com>
+
+	[base] Improve emboldener (#45596).
+
+	* src/base/ftoutln.c (FT_Outline_EmboldenXY): Correct displacement
+	of zero-lenght segments.
+
 2015-08-16  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
 	[base] Reoptimize arithmetic.
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index 8804cc7..297db2e 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -908,8 +908,7 @@
                          FT_Pos       ystrength )
   {
     FT_Vector*  points;
-    FT_Vector   v_prev, v_first, v_next, v_cur;
-    FT_Int      c, n, first;
+    FT_Int      c, first, last;
     FT_Int      orientation;
 
 
@@ -935,76 +934,94 @@
     first = 0;
     for ( c = 0; c < outline->n_contours; c++ )
     {
-      FT_Vector  in, out, shift;
-      FT_Fixed   l_in, l_out, l, q, d;
-      FT_Int     last = outline->contours[c];
-
+      FT_Vector  in, out, anchor, shift;
+      FT_Fixed   l_in = 0, l_out, l_anchor, l, q, d;
+      FT_Int     i, j, k;
 
-      v_first = points[first];
-      v_prev  = points[last];
-      v_cur   = v_first;
 
-      /* compute incoming normalized vector */
-      in.x = v_cur.x - v_prev.x;
-      in.y = v_cur.y - v_prev.y;
-      l_in = (FT_Fixed)FT_Vector_NormLen( &in );
+      last = outline->contours[c];
 
-      for ( n = first; n <= last; n++ )
+      /* Counter i cycles though the points; counter j advances only   */
+      /* when points are moved; anchor k markes the first moved point. */
+      for ( i = last, j = first, k = -1;
+            j != i && i != k;
+            j = j < last ? j + 1 : first )
       {
-        if ( n < last )
-          v_next = points[n + 1];
+        if ( j != k )
+        {
+          out.x = points[j].x - points[i].x;
+          out.y = points[j].y - points[i].y;
+          l_out = FT_Vector_NormLen( &out );
+        }
         else
-          v_next = v_first;
-
-        /* compute outgoing normalized vector */
-        out.x = v_next.x - v_cur.x;
-        out.y = v_next.y - v_cur.y;
-        l_out = (FT_Fixed)FT_Vector_NormLen( &out );
+        {
+          out   = anchor;
+          l_out = l_anchor;
+        }
 
-        d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );
+        if ( l_out == 0 )
+          continue;
 
-        /* shift only if turn is less than ~160 degrees */
-        if ( d > -0xF000L )
+        if ( l_in != 0 )
         {
-          d = d + 0x10000L;
+          if ( k < 0 )
+          {
+            k = i;
+            anchor   = in;
+            l_anchor = l_in;
+          }
 
-          /* shift along lateral bisector in appropriate orientation */
-          shift.x = in.y + out.y;
-          shift.y = in.x + out.x;
+          d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );
 
-          if ( orientation == FT_ORIENTATION_TRUETYPE )
-            shift.x = -shift.x;
-          else
-            shift.y = -shift.y;
+          /* shift only if turn is less than ~160 degrees */
+          if ( d > -0xF000L )
+          {
+            d = d + 0x10000L;
 
-          /* restrict shift magnitude to better handle collapsing segments */
-          q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x );
-          if ( orientation == FT_ORIENTATION_TRUETYPE )
-            q = -q;
+            /* shift components along lateral bisector in proper orientation */
+            shift.x = in.y + out.y;
+            shift.y = in.x + out.x;
 
-          l = FT_MIN( l_in, l_out );
+            if ( orientation == FT_ORIENTATION_TRUETYPE )
+              shift.x = -shift.x;
+            else
+              shift.y = -shift.y;
 
-          /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
-          if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) )
-            shift.x = FT_MulDiv( shift.x, xstrength, d );
-          else
-            shift.x = FT_MulDiv( shift.x, l, q );
+            /* restrict shift magnitude to better handle collapsing segments */
+            q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x );
+            if ( orientation == FT_ORIENTATION_TRUETYPE )
+              q = -q;
+
+            l = FT_MIN( l_in, l_out );
+
+            /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
+            if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) )
+              shift.x = FT_MulDiv( shift.x, xstrength, d );
+            else
+              shift.x = FT_MulDiv( shift.x, l, q );
 
 
-          if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) )
-            shift.y = FT_MulDiv( shift.y, ystrength, d );
+            if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) )
+              shift.y = FT_MulDiv( shift.y, ystrength, d );
+            else
+              shift.y = FT_MulDiv( shift.y, l, q );
+          }
           else
-            shift.y = FT_MulDiv( shift.y, l, q );
+            shift.x = shift.y = 0;
+
+          for ( ;
+                i != j;
+                i = i < last ? i + 1 : first )
+          {
+            points[i].x += xstrength + shift.x;
+            points[i].y += ystrength + shift.y;
+          }
         }
         else
-          shift.x = shift.y = 0;
-
-        points[n].x = v_cur.x + xstrength + shift.x;
-        points[n].y = v_cur.y + ystrength + shift.y;
+          i = j;
 
-        in    = out;
-        l_in  = l_out;
-        v_cur = v_next;
+        in   = out;
+        l_in = l_out;
       }
 
       first = last + 1;