Commit 890f807a7b053179b42860a32fe9a0ed835be2be

Wu, Chia-I (吳佳一) 2006-02-22T20:47:39

* include/freetype/ftoutln.h (enum FT_Orientation): New value `FT_ORIENTATION_NONE'. * src/base/ftoutln.c (FT_OUTLINE_GET_CONTOUR, ft_contour_has, ft_contour_enclosed, ft_outline_get_orientation): Another version of `FT_Outline_Get_Orientation'. This version differs from the public one in that each part (contour not enclosed in another contour) of the outline is checked for orientation. (FT_Outline_Embolden): Use `ft_outline_get_orientation'. * src/base/ftsynth.c (FT_GlyphSlot_Embolden): Render the outline and use bitmap's embolden routine when the outline one failed.

diff --git a/ChangeLog b/ChangeLog
index 749ef14..5031e66 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-02-23  Chia-I Wu  <b90201047@ntu.edu.tw>
+
+	* include/freetype/ftoutln.h (enum FT_Orientation): New value
+	`FT_ORIENTATION_NONE'.
+
+	* src/base/ftoutln.c (FT_OUTLINE_GET_CONTOUR, ft_contour_has,
+	ft_contour_enclosed, ft_outline_get_orientation): Another version of
+	`FT_Outline_Get_Orientation'.  This version differs from the public
+	one in that each part (contour not enclosed in another contour) of the
+	outline is checked for orientation.
+	(FT_Outline_Embolden): Use `ft_outline_get_orientation'.
+
+	* src/base/ftsynth.c (FT_GlyphSlot_Embolden): Render the outline and
+	use bitmap's embolden routine when the outline one failed.
+
 2006-02-22  Chia-I Wu  <b90201047@ntu.edu.tw>
 
 	* modules.cfg: Compile in ftotval.c and ftxf86.c by default for ABI
diff --git a/include/freetype/ftoutln.h b/include/freetype/ftoutln.h
index 946af73..8939030 100644
--- a/include/freetype/ftoutln.h
+++ b/include/freetype/ftoutln.h
@@ -465,13 +465,19 @@ FT_BEGIN_HEADER
   *     This is identical to @FT_ORIENTATION_POSTSCRIPT, but is used to
   *     remember that in Postscript, everything that is to the left of
   *     the drawing direction of a contour must be filled.
+  *
+  *   FT_ORIENTATION_NONE ::
+  *     The orientation cannot be determined.  That is, different part of the
+  *     glyph has different orientation.
+  *
   */
   typedef enum
   {
     FT_ORIENTATION_TRUETYPE   = 0,
     FT_ORIENTATION_POSTSCRIPT = 1,
     FT_ORIENTATION_FILL_RIGHT = FT_ORIENTATION_TRUETYPE,
-    FT_ORIENTATION_FILL_LEFT  = FT_ORIENTATION_POSTSCRIPT
+    FT_ORIENTATION_FILL_LEFT  = FT_ORIENTATION_POSTSCRIPT,
+    FT_ORIENTATION_NONE
   
   } FT_Orientation;
 
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index a252b22..b9f8459 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -668,6 +668,168 @@
   }
 
 
+#define FT_OUTLINE_GET_CONTOUR( outline, c, first, last )      \
+  do {                                                         \
+    ( first ) = ( c > 0 ) ? ( outline )->points +              \
+                            ( outline )->contours[c - 1] + 1   \
+                          : ( outline )->points;               \
+    ( last ) = ( outline )->points + ( outline )->contours[c]; \
+  } while ( 0 )
+
+
+  /* Is a point in some contour?                  */
+  /*                                              */
+  /* We treat every point of the contour as if it */
+  /* it is ON.  That is, we allow false positive, */
+  /* but disallow false negative. (XXX really?)   */
+  static FT_Bool
+  ft_contour_has( FT_Outline*  outline,
+                  FT_Short     c,
+                  FT_Vector*   point )
+  {
+    FT_Vector*  first;
+    FT_Vector*  last;
+    FT_Vector*  a;
+    FT_Vector*  b;
+    FT_UInt     n = 0;
+
+
+    FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
+
+    for ( a = first; a <= last; a++ )
+    {
+      FT_Pos  x;
+      FT_Int  intersect;
+
+
+      b = ( a == last ) ? first : a + 1;
+
+      intersect = ( a->y - point->y ) ^ ( b->y - point->y );
+
+      /* a and b are on the same side */
+      if ( intersect >= 0 )
+      {
+        if ( intersect == 0 && a->y == point->y )
+        {
+          if ( ( a->x <= point->x && b->x >= point->x ) ||
+               ( a->x >= point->x && b->x <= point->x ) )
+            return 1;
+        }
+
+        continue;
+      }
+
+      x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y );
+
+      if ( x < point->x )
+        n++;
+      else if ( x == point->x )
+        return 1;
+    }
+
+    return ( n % 2 );
+  }
+
+  
+  static FT_Bool
+  ft_contour_enclosed( FT_Outline*  outline,
+                       FT_UShort    c )
+  {
+    FT_Vector*  first;
+    FT_Vector*  last;
+    FT_Short    i;
+
+
+    FT_OUTLINE_GET_CONTOUR( outline, c, first, last );
+
+    for ( i = 0; i < outline->n_contours; i++ )
+    {
+      if ( i != c && ft_contour_has( outline, i, first ) )
+      {
+        FT_Vector*  pt;
+
+
+        for ( pt = first + 1; pt <= last; pt++ )
+          if ( !ft_contour_has( outline, i, pt ) )
+            return 0;
+
+        return 1;
+      }
+    }
+
+    return 0;
+  }
+
+
+  /* This version differs from the public one in that each */
+  /* part (contour not enclosed in another contour) of the */
+  /* outline is checked for orientation.  This is          */
+  /* necessary for some buggy CJK fonts.                   */
+  static FT_Orientation
+  ft_outline_get_orientation( FT_Outline*  outline )
+  {
+    FT_Short        i;
+    FT_Vector*      first;
+    FT_Vector*      last;
+    FT_Orientation  orient = FT_ORIENTATION_NONE;
+
+
+    first = outline->points;
+    for ( i = 0; i < outline->n_contours; i++, first = last + 1 )
+    {
+      FT_Vector*  point;
+      FT_Vector*  xmin_point;
+      FT_Pos      xmin;
+
+
+      last = outline->points + outline->contours[i];
+
+      /* skip degenerate contours */
+      if ( last < first + 2 )
+        continue;
+
+      if ( ft_contour_enclosed( outline, i ) )
+        continue;
+
+      xmin       = first->x;
+      xmin_point = first;
+
+      for ( point = first + 1; point <= last; point++ )
+      {
+        if ( point->x < xmin )
+        {
+          xmin       = point->x;
+          xmin_point = point;
+        }
+      }
+
+      /* check the orientation of the contour */
+      {
+        FT_Vector*      prev;
+        FT_Vector*      next;
+        FT_Orientation  o;
+
+
+        prev = ( xmin_point == first ) ? last : xmin_point - 1;
+        next = ( xmin_point == last ) ? first : xmin_point + 1;
+
+        if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
+             FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
+          o = FT_ORIENTATION_POSTSCRIPT;
+        else
+          o = FT_ORIENTATION_TRUETYPE;
+
+        if ( orient == FT_ORIENTATION_NONE )
+          orient = o;
+        else if ( orient != o )
+          return FT_ORIENTATION_NONE;
+      }
+    }
+
+    return orient;
+  }
+
+
   /* documentation is in ftoutln.h */
 
   FT_EXPORT_DEF( FT_Error )
@@ -678,6 +840,7 @@
     FT_Vector   v_prev, v_first, v_next, v_cur;
     FT_Angle    rotate, angle_in, angle_out;
     FT_Int      c, n, first;
+    FT_Int      orientation;
 
 
     if ( !outline )
@@ -687,7 +850,16 @@
     if ( strength == 0 )
       return FT_Err_Ok;
 
-    if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_TRUETYPE )
+    orientation = ft_outline_get_orientation( outline );
+    if ( orientation == FT_ORIENTATION_NONE )
+    {
+      if ( outline->n_contours )
+        return FT_Err_Invalid_Argument;
+      else
+        return FT_Err_Ok;
+    }
+
+    if ( orientation == FT_ORIENTATION_TRUETYPE )
       rotate = -FT_ANGLE_PI2;
     else
       rotate = FT_ANGLE_PI2;
diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c
index 07a1716..ebb86a8 100644
--- a/src/base/ftsynth.c
+++ b/src/base/ftsynth.c
@@ -75,10 +75,14 @@
   {
     FT_Library  library = slot->library;
     FT_Face     face    = FT_SLOT_FACE( slot );
-    FT_Error    error   = FT_Err_Ok;
+    FT_Error    error;
     FT_Pos      xstr, ystr;
 
 
+    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
+         slot->format != FT_GLYPH_FORMAT_BITMAP )
+      return;
+
     /* some reasonable strength */
     xstr = FT_MulFix( face->units_per_EM,
                       face->size->metrics.y_scale ) / 24;
@@ -87,13 +91,22 @@
     if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
     {
       error = FT_Outline_Embolden( &slot->outline, xstr );
-
-      /* this is more than enough for most glyphs;                         */
-      /* if you need accurate values, you have to call FT_Outline_Get_CBox */
-      xstr = xstr * 2;
-      ystr = xstr;
+      if ( error )
+      {
+        error = FT_Render_Glyph( slot, FT_RENDER_MODE_NORMAL );
+        if ( error )
+          return;
+      }
+      else
+      {
+        /* this is more than enough for most glyphs;                         */
+        /* if you need accurate values, you have to call FT_Outline_Get_CBox */
+        xstr = xstr * 2;
+        ystr = xstr;
+      }
     }
-    else if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
+
+    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
     {
       xstr = FT_PIX_FLOOR( xstr );
       if ( xstr == 0 )
@@ -108,37 +121,31 @@
 
         FT_Bitmap_New( &bitmap );
         error = FT_Bitmap_Copy( library, &slot->bitmap, &bitmap );
+        if ( error )
+          return;
 
-        if ( !error )
-        {
-          slot->bitmap = bitmap;
-          slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
-        }
+        slot->bitmap = bitmap;
+        slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
       }
 
-      if ( !error )
-        error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr );
+      error = FT_Bitmap_Embolden( library, &slot->bitmap, xstr, ystr );
+      if ( error )
+        return;
     }
-    else
-      error = FT_Err_Invalid_Argument;
 
-    /* modify the metrics accordingly */
-    if ( !error )
-    {
-      /* assume the layout is horizontal */
-      slot->advance.x += xstr;
-
-      slot->metrics.width        += xstr;
-      slot->metrics.height       += ystr;
-      slot->metrics.horiBearingY += ystr;
-      slot->metrics.horiAdvance  += xstr;
-      slot->metrics.vertBearingX -= xstr / 2;
-      slot->metrics.vertBearingY += ystr;
-      slot->metrics.vertAdvance  += ystr;
-
-      if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
-        slot->bitmap_top += ystr >> 6;
-    }
+    /* assume the layout is horizontal */
+    slot->advance.x += xstr;
+
+    slot->metrics.width        += xstr;
+    slot->metrics.height       += ystr;
+    slot->metrics.horiBearingY += ystr;
+    slot->metrics.horiAdvance  += xstr;
+    slot->metrics.vertBearingX -= xstr / 2;
+    slot->metrics.vertBearingY += ystr;
+    slot->metrics.vertAdvance  += ystr;
+
+    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
+      slot->bitmap_top += ystr >> 6;
   }