Commit c136b409eb0a9a9e5ffeb27ee0488ea4c7e0f09b

David Turner 2000-05-04T17:24:54

an update to FT_Outline_Funcs used to improve the accuracy of outline decomposition

diff --git a/include/ftimage.h b/include/ftimage.h
index 24d2d6b..01f6bad 100644
--- a/include/ftimage.h
+++ b/include/ftimage.h
@@ -467,6 +467,9 @@
     FT_Outline_ConicTo_Func  conic_to;
     FT_Outline_CubicTo_Func  cubic_to;
 
+    int                      shift;
+    FT_Pos                   delta;
+
   } FT_Outline_Funcs;
 
 
diff --git a/src/base/ftgrays.c b/src/base/ftgrays.c
index 927b7a4..9362f0b 100644
--- a/src/base/ftgrays.c
+++ b/src/base/ftgrays.c
@@ -1241,7 +1241,9 @@ int  check_sort( PCell  cells, int count )
       (FT_Outline_MoveTo_Func)Move_To,
       (FT_Outline_LineTo_Func)Line_To,
       (FT_Outline_ConicTo_Func)Conic_To,
-      (FT_Outline_CubicTo_Func)Cubic_To
+      (FT_Outline_CubicTo_Func)Cubic_To,
+      0,
+      0
     };
 
     TBand    bands[40], *band;
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index 43ec6db..f63115f 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -56,6 +56,195 @@
   /* <Return>                                                              */
   /*    Error code.  0 means sucess.                                       */
   /*                                                                       */
+#if 1
+
+  EXPORT_FUNC
+  int  FT_Outline_Decompose( FT_Outline*        outline,
+                             FT_Outline_Funcs*  interface,
+                             void*              user )
+  {
+#undef SCALED
+#define SCALED( x )   ( ((x) << shift) - delta )
+
+    FT_Vector  v_last;
+    FT_Vector  v_control;
+    FT_Vector  v_start;
+
+    FT_Vector* point;
+    FT_Vector* limit;
+    char*      tags;
+
+    int    n;         /* index of contour in outline     */
+    int    first;     /* index of first point in contour */
+    int    error;
+    char   tag;       /* current point's state           */
+
+    int    shift   = interface->shift;
+    FT_Pos delta   = interface->delta;
+
+    first = 0;
+
+    for ( n = 0; n < outline->n_contours; n++ )
+    {
+      int  last;  /* index of last point in contour */
+
+      last  = outline->contours[n];
+      limit = outline->points + last;
+
+      v_start = outline->points[first];
+      v_last  = outline->points[last];
+      
+      v_start.x = SCALED(v_start.x);  v_start.y = SCALED(v_start.y);
+      v_last.x  = SCALED(v_last.x);   v_last.y  = SCALED(v_last.y);
+
+      v_control = v_start;
+
+      point = outline->points + first;
+      tags  = outline->tags  + first;
+      tag   = FT_CURVE_TAG( tags[0] );
+
+      /* A contour cannot start with a cubic control point! */
+      if ( tag == FT_Curve_Tag_Cubic )
+        goto Invalid_Outline;
+
+      /* check first point to determine origin */
+      if ( tag == FT_Curve_Tag_Conic )
+      {
+        /* first point is conic control.  Yes, this happens. */
+        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
+        {
+          /* start at last point if it is on the curve */
+          v_start = v_last;
+          limit--;
+        }
+        else
+        {
+          /* if both first and last points are conic,         */
+          /* start at their middle and record its position    */
+          /* for closure                                      */
+          v_start.x = ( v_start.x + v_last.x ) / 2;
+          v_start.y = ( v_start.y + v_last.y ) / 2;
+
+          v_last = v_start;
+        }
+        point--;
+        tags--;
+      }
+
+      error = interface->move_to( &v_start, user );
+      if (error) goto Exit;
+
+      while (point < limit)
+      {
+        point++;
+        tags++;
+  
+        tag = FT_CURVE_TAG( tags[0] );
+        switch (tag)
+        {
+          case FT_Curve_Tag_On:  /* emit a single line_to */
+            {
+              FT_Vector  vec;
+              
+              vec.x = SCALED(point->x);
+              vec.y = SCALED(point->y);
+              
+              error = interface->line_to( &vec, user );
+              if (error) goto Exit;
+              continue;
+            }
+
+          
+          case FT_Curve_Tag_Conic:  /* consume conic arcs */
+            {
+              v_control.x = SCALED(point->x);
+              v_control.y = SCALED(point->y);
+              
+            Do_Conic:
+              if (point < limit)
+              {
+                FT_Vector  vec;
+                FT_Vector  v_middle;
+                
+                point++;
+                tags++;
+                tag = FT_CURVE_TAG( tags[0] );
+                
+                vec.x = SCALED(point->x);
+                vec.y = SCALED(point->y);
+                
+                if (tag == FT_Curve_Tag_On)
+                {
+                  error = interface->conic_to( &v_control, &vec, user );
+                  if (error) goto Exit;
+                  continue;
+                }
+                
+                if (tag != FT_Curve_Tag_Conic)
+                  goto Invalid_Outline;
+  
+                v_middle.x = (v_control.x + vec.x)/2;
+                v_middle.y = (v_control.y + vec.y)/2;
+  
+                error = interface->conic_to( &v_control, &v_middle, user );
+                if (error) goto Exit;
+                
+                v_control = vec;
+                goto Do_Conic;
+              }
+              
+              error = interface->conic_to( &v_control, &v_start, user );
+              goto Close;
+            }
+          
+          default:  /* FT_Curve_Tag_Cubic */
+            {
+              FT_Vector  vec1, vec2;
+              
+              if ( point+1 > limit         ||
+                   FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+                goto Invalid_Outline;
+                
+              point += 2;
+              tags  += 2;
+              
+              vec1.x = SCALED(point[-2].x);  vec1.y = SCALED(point[-2].y);
+              vec2.x = SCALED(point[-1].x);  vec2.y = SCALED(point[-1].y);
+
+              if (point <= limit)
+              {
+                FT_Vector  vec;
+                
+                vec.x = SCALED(point->x);
+                vec.y = SCALED(point->y);
+                
+                error = interface->cubic_to( &vec1, &vec2, &vec, user );
+                if (error) goto Exit;
+                continue;
+              }
+              
+              error = interface->cubic_to( &vec1, &vec2, &v_start, user );
+              goto Close;
+            }
+        }
+      }
+
+      /* close the contour with a line segment */
+      error = interface->line_to( &v_start, user );
+      
+   Close:
+      if (error) goto Exit;
+      first = last+1;
+    }
+
+    return 0;
+  Exit:
+    return error;
+    
+  Invalid_Outline:
+    return -1;
+  }
+#else
   EXPORT_FUNC
   int  FT_Outline_Decompose( FT_Outline*        outline,
                              FT_Outline_Funcs*  interface,
@@ -224,7 +413,7 @@
   Invalid_Outline:
     return -1;
   }
-
+#endif
 
   /*************************************************************************/
   /*                                                                       */
diff --git a/src/base/ftraster.c b/src/base/ftraster.c
index bac067b..82ecd0e 100644
--- a/src/base/ftraster.c
+++ b/src/base/ftraster.c
@@ -2283,7 +2283,9 @@
       (FT_Outline_MoveTo_Func)Move_To,
       (FT_Outline_LineTo_Func)Line_To,
       (FT_Outline_ConicTo_Func)Conic_To,
-      (FT_Outline_CubicTo_Func)Cubic_To
+      (FT_Outline_CubicTo_Func)Cubic_To,
+      0,
+      0
     };
 
     /* Set up state in the raster object */