tizen 2.3.1 release
[framework/graphics/freetype.git] / src / base / ftoutln.c
index 9ae276d..8749d64 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    FreeType outline management (body).                                  */
 /*                                                                         */
-/*  Copyright 1996-2008, 2010, 2012 by                                     */
+/*  Copyright 1996-2008, 2010, 2012-2014 by                                */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -26,6 +26,7 @@
 #include <ft2build.h>
 #include FT_OUTLINE_H
 #include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CALC_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_TRIGONOMETRY_H
 
     FT_Pos   delta;
 
 
-    if ( !outline || !func_interface )
-      return FT_Err_Invalid_Argument;
+    if ( !outline )
+      return FT_THROW( Invalid_Outline );
+
+    if ( !func_interface )
+      return FT_THROW( Invalid_Argument );
 
     shift = func_interface->shift;
     delta = func_interface->delta;
           v_start.x = ( v_start.x + v_last.x ) / 2;
           v_start.y = ( v_start.y + v_last.y ) / 2;
 
-          v_last = v_start;
+       /* v_last = v_start; */
         }
         point--;
         tags--;
     return error;
 
   Invalid_Outline:
-    return FT_Err_Invalid_Outline;
+    return FT_THROW( Invalid_Outline );
   }
 
 
 
 
     if ( !anoutline || !memory )
-      return FT_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
     *anoutline = null_outline;
 
+    if ( numContours < 0                  ||
+         (FT_UInt)numContours > numPoints )
+      return FT_THROW( Invalid_Argument );
+
+    if ( numPoints > FT_OUTLINE_POINTS_MAX )
+      return FT_THROW( Array_Too_Large );
+
     if ( FT_NEW_ARRAY( anoutline->points,   numPoints   ) ||
          FT_NEW_ARRAY( anoutline->tags,     numPoints   ) ||
          FT_NEW_ARRAY( anoutline->contours, numContours ) )
                   FT_Outline  *anoutline )
   {
     if ( !library )
-      return FT_Err_Invalid_Library_Handle;
+      return FT_THROW( Invalid_Library_Handle );
 
     return FT_Outline_New_Internal( library->memory, numPoints,
                                     numContours, anoutline );
 
       /* empty glyph? */
       if ( n_points == 0 && n_contours == 0 )
-        return 0;
+        return FT_Err_Ok;
 
       /* check point and contour counts */
       if ( n_points <= 0 || n_contours <= 0 )
         goto Bad;
 
       /* XXX: check the tags array */
-      return 0;
+      return FT_Err_Ok;
     }
 
   Bad:
-    return FT_Err_Invalid_Argument;
+    return FT_THROW( Invalid_Argument );
   }
 
 
     FT_Int  is_owner;
 
 
-    if ( !source            || !target            ||
-         source->n_points   != target->n_points   ||
+    if ( !source || !target )
+      return FT_THROW( Invalid_Outline );
+
+    if ( source->n_points   != target->n_points   ||
          source->n_contours != target->n_contours )
-      return FT_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
     if ( source == target )
       return FT_Err_Ok;
   FT_Outline_Done_Internal( FT_Memory    memory,
                             FT_Outline*  outline )
   {
-    if ( memory && outline )
-    {
-      if ( outline->flags & FT_OUTLINE_OWNER )
-      {
-        FT_FREE( outline->points   );
-        FT_FREE( outline->tags     );
-        FT_FREE( outline->contours );
-      }
-      *outline = null_outline;
+    if ( !outline )
+      return FT_THROW( Invalid_Outline );
 
-      return FT_Err_Ok;
+    if ( !memory )
+      return FT_THROW( Invalid_Argument );
+
+    if ( outline->flags & FT_OUTLINE_OWNER )
+    {
+      FT_FREE( outline->points   );
+      FT_FREE( outline->tags     );
+      FT_FREE( outline->contours );
     }
-    else
-      return FT_Err_Invalid_Argument;
+    *outline = null_outline;
+
+    return FT_Err_Ok;
   }
 
 
     /* check for valid `outline' in FT_Outline_Done_Internal() */
 
     if ( !library )
-      return FT_Err_Invalid_Library_Handle;
+      return FT_THROW( Invalid_Library_Handle );
 
     return FT_Outline_Done_Internal( library->memory, outline );
   }
       {
         char*  p = outline->tags + first;
         char*  q = outline->tags + last;
-        char   swap;
 
 
         while ( p < q )
         {
+          char  swap;
+
+
           swap = *p;
           *p   = *q;
           *q   = swap;
 
 
     if ( !library )
-      return FT_Err_Invalid_Library_Handle;
+      return FT_THROW( Invalid_Library_Handle );
 
-    if ( !outline || !params )
-      return FT_Err_Invalid_Argument;
+    if ( !outline )
+      return FT_THROW( Invalid_Outline );
+
+    if ( !params )
+      return FT_THROW( Invalid_Argument );
 
     renderer = library->cur_renderer;
     node     = library->renderers.head;
 
     params->source = (void*)outline;
 
-    error = FT_Err_Cannot_Render_Glyph;
+    error = FT_ERR( Cannot_Render_Glyph );
     while ( renderer )
     {
       error = renderer->raster_render( renderer->raster, params );
-      if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+      if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) )
         break;
 
       /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
     /* if we changed the current renderer for the glyph image format */
     /* we need to select it as the next current one                  */
     if ( !error && update && renderer )
-      FT_Set_Renderer( library, renderer, 0, 0 );
+      error = FT_Set_Renderer( library, renderer, 0, 0 );
 
     return error;
   }
 
 
     if ( !abitmap )
-      return FT_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
-    /* other checks are delayed to FT_Outline_Render() */
+    /* other checks are delayed to `FT_Outline_Render' */
 
     params.target = abitmap;
     params.flags  = 0;
 #if 0
 
 #define FT_OUTLINE_GET_CONTOUR( outline, c, first, last )  \
-  do {                                                     \
+  do                                                       \
+  {                                                        \
     (first) = ( c > 0 ) ? (outline)->points +              \
                             (outline)->contours[c - 1] + 1 \
                         : (outline)->points;               \
   FT_Outline_Embolden( FT_Outline*  outline,
                        FT_Pos       strength )
   {
+    return FT_Outline_EmboldenXY( outline, strength, strength );
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_EmboldenXY( FT_Outline*  outline,
+                         FT_Pos       xstrength,
+                         FT_Pos       ystrength )
+  {
     FT_Vector*  points;
     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 )
-      return FT_Err_Invalid_Argument;
+      return FT_THROW( Invalid_Outline );
 
-    strength /= 2;
-    if ( strength == 0 )
+    xstrength /= 2;
+    ystrength /= 2;
+    if ( xstrength == 0 && ystrength == 0 )
       return FT_Err_Ok;
 
     orientation = FT_Outline_Get_Orientation( outline );
     if ( orientation == FT_ORIENTATION_NONE )
     {
       if ( outline->n_contours )
-        return FT_Err_Invalid_Argument;
+        return FT_THROW( Invalid_Argument );
       else
         return FT_Err_Ok;
     }
 
-    if ( orientation == FT_ORIENTATION_TRUETYPE )
-      rotate = -FT_ANGLE_PI2;
-    else
-      rotate = FT_ANGLE_PI2;
-
     points = outline->points;
 
     first = 0;
     for ( c = 0; c < outline->n_contours; c++ )
     {
-      int  last = outline->contours[c];
+      FT_Vector  in, out, shift;
+      FT_Fixed   l_in, l_out, l, q, d;
+      int        last = outline->contours[c];
 
 
       v_first = points[first];
       v_prev  = points[last];
       v_cur   = v_first;
 
-      for ( n = first; n <= last; n++ )
+      /* compute incoming normalized vector */
+      in.x = v_cur.x - v_prev.x;
+      in.y = v_cur.y - v_prev.y;
+      l_in = FT_Vector_Length( &in );
+      if ( l_in )
       {
-        FT_Vector  in, out;
-        FT_Angle   angle_diff;
-        FT_Pos     d;
-        FT_Fixed   scale;
-
+        in.x = FT_DivFix( in.x, l_in );
+        in.y = FT_DivFix( in.y, l_in );
+      }
 
+      for ( n = first; n <= last; n++ )
+      {
         if ( n < last )
           v_next = points[n + 1];
         else
           v_next = v_first;
 
-        /* compute the in and out vectors */
-        in.x = v_cur.x - v_prev.x;
-        in.y = v_cur.y - v_prev.y;
-
+        /* compute outgoing normalized vector */
         out.x = v_next.x - v_cur.x;
         out.y = v_next.y - v_cur.y;
+        l_out = FT_Vector_Length( &out );
+        if ( l_out )
+        {
+          out.x = FT_DivFix( out.x, l_out );
+          out.y = FT_DivFix( out.y, l_out );
+        }
 
-        angle_in   = FT_Atan2( in.x, in.y );
-        angle_out  = FT_Atan2( out.x, out.y );
-        angle_diff = FT_Angle_Diff( angle_in, angle_out );
-        scale      = FT_Cos( angle_diff / 2 );
+        d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y );
 
-        if ( scale < 0x4000L && scale > -0x4000L )
-          in.x = in.y = 0;
-        else
+        /* shift only if turn is less than ~160 degrees */
+        if ( d > -0xF000L )
         {
-          d = FT_DivFix( strength, scale );
+          d = d + 0x10000L;
+
+          /* shift components are aligned along lateral bisector */
+          /* and directed according to the outline orientation.  */
+          shift.x = in.y + out.y;
+          shift.y = in.x + out.x;
+
+          if ( orientation == FT_ORIENTATION_TRUETYPE )
+            shift.x = -shift.x;
+          else
+            shift.y = -shift.y;
+
+          /* 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 );
 
-          FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
+          /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
+          if ( FT_MulFix( xstrength, q ) <= FT_MulFix( d, l ) )
+            shift.x = FT_MulDiv( shift.x, xstrength, d );
+          else
+            shift.x = FT_MulDiv( shift.x, l, q );
+
+
+          if ( FT_MulFix( ystrength, q ) <= FT_MulFix( d, l ) )
+            shift.y = FT_MulDiv( shift.y, ystrength, d );
+          else
+            shift.y = FT_MulDiv( shift.y, l, q );
         }
+        else
+          shift.x = shift.y = 0;
 
-        outline->points[n].x = v_cur.x + strength + in.x;
-        outline->points[n].y = v_cur.y + strength + in.y;
+        outline->points[n].x = v_cur.x + xstrength + shift.x;
+        outline->points[n].y = v_cur.y + ystrength + shift.y;
 
-        v_prev = v_cur;
-        v_cur  = v_next;
+        in    = out;
+        l_in  = l_out;
+        v_cur = v_next;
       }
 
       first = last + 1;
   FT_EXPORT_DEF( FT_Orientation )
   FT_Outline_Get_Orientation( FT_Outline*  outline )
   {
-    FT_Pos      xmin       = 32768L;
-    FT_Pos      xmin_ymin  = 32768L;
-    FT_Pos      xmin_ymax  = -32768L;
-    FT_Vector*  xmin_first = NULL;
-    FT_Vector*  xmin_last  = NULL;
-
-    short*      contour;
-
-    FT_Vector*  first;
-    FT_Vector*  last;
-    FT_Vector*  prev;
-    FT_Vector*  point;
-
-    int             i;
-    FT_Pos          ray_y[3];
-    FT_Orientation  result[3] =
-      { FT_ORIENTATION_NONE, FT_ORIENTATION_NONE, FT_ORIENTATION_NONE };
+    FT_BBox     cbox;
+    FT_Int      xshift, yshift;
+    FT_Vector*  points;
+    FT_Vector   v_prev, v_cur;
+    FT_Int      c, n, first;
+    FT_Pos      area = 0;
 
 
     if ( !outline || outline->n_points <= 0 )
     /* cubic or quadratic curves, this test deals with the polygon    */
     /* only which is spanned up by the control points.                */
 
-    first = outline->points;
-    for ( contour = outline->contours;
-          contour < outline->contours + outline->n_contours;
-          contour++, first = last + 1 )
-    {
-      FT_Pos  contour_xmin = 32768L;
-      FT_Pos  contour_xmax = -32768L;
-      FT_Pos  contour_ymin = 32768L;
-      FT_Pos  contour_ymax = -32768L;
-
+    FT_Outline_Get_CBox( outline, &cbox );
 
-      last = outline->points + *contour;
+    /* Handle collapsed outlines to avoid undefined FT_MSB. */
+    if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax )
+      return FT_ORIENTATION_NONE;
 
-      /* skip degenerate contours */
-      if ( last < first + 2 )
-        continue;
+    xshift = FT_MSB( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) - 14;
+    xshift = FT_MAX( xshift, 0 );
 
-      for ( point = first; point <= last; ++point )
-      {
-        if ( point->x < contour_xmin )
-          contour_xmin = point->x;
+    yshift = FT_MSB( cbox.yMax - cbox.yMin ) - 14;
+    yshift = FT_MAX( yshift, 0 );
 
-        if ( point->x > contour_xmax )
-          contour_xmax = point->x;
-
-        if ( point->y < contour_ymin )
-          contour_ymin = point->y;
-
-        if ( point->y > contour_ymax )
-          contour_ymax = point->y;
-      }
-
-      if ( contour_xmin < xmin          &&
-           contour_xmin != contour_xmax &&
-           contour_ymin != contour_ymax )
-      {
-        xmin       = contour_xmin;
-        xmin_ymin  = contour_ymin;
-        xmin_ymax  = contour_ymax;
-        xmin_first = first;
-        xmin_last  = last;
-      }
-    }
-
-    if ( xmin == 32768L )
-      return FT_ORIENTATION_TRUETYPE;
-
-    ray_y[0] = ( xmin_ymin * 3 + xmin_ymax     ) >> 2;
-    ray_y[1] = ( xmin_ymin     + xmin_ymax     ) >> 1;
-    ray_y[2] = ( xmin_ymin     + xmin_ymax * 3 ) >> 2;
+    points = outline->points;
 
-    for ( i = 0; i < 3; i++ )
+    first = 0;
+    for ( c = 0; c < outline->n_contours; c++ )
     {
-      FT_Pos      left_x;
-      FT_Pos      right_x;
-      FT_Vector*  left1;
-      FT_Vector*  left2;
-      FT_Vector*  right1;
-      FT_Vector*  right2;
-
+      FT_Int  last = outline->contours[c];
 
-    RedoRay:
-      left_x  = 32768L;
-      right_x = -32768L;
 
-      left1 = left2 = right1 = right2 = NULL;
+      v_prev = points[last];
 
-      prev = xmin_last;
-      for ( point = xmin_first; point <= xmin_last; prev = point, ++point )
+      for ( n = first; n <= last; n++ )
       {
-        FT_Pos  tmp_x;
-
-
-        if ( point->y == ray_y[i] || prev->y == ray_y[i] )
-        {
-          ray_y[i]++;
-          goto RedoRay;
-        }
-
-        if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) ||
-             ( point->y > ray_y[i] && prev->y > ray_y[i] ) )
-          continue;
-
-        tmp_x = FT_MulDiv( point->x - prev->x,
-                           ray_y[i] - prev->y,
-                           point->y - prev->y ) + prev->x;
-
-        if ( tmp_x < left_x )
-        {
-          left_x = tmp_x;
-          left1  = prev;
-          left2  = point;
-        }
-
-        if ( tmp_x > right_x )
-        {
-          right_x = tmp_x;
-          right1  = prev;
-          right2  = point;
-        }
+        v_cur = points[n];
+        area += ( ( v_cur.y - v_prev.y ) >> yshift ) *
+                ( ( v_cur.x + v_prev.x ) >> xshift );
+        v_prev = v_cur;
       }
 
-      if ( left1 && right1 )
-      {
-        if ( left1->y < left2->y && right1->y > right2->y )
-          result[i] = FT_ORIENTATION_TRUETYPE;
-        else if ( left1->y > left2->y && right1->y < right2->y )
-          result[i] = FT_ORIENTATION_POSTSCRIPT;
-        else
-          result[i] = FT_ORIENTATION_NONE;
-      }
+      first = last + 1;
     }
 
-    if ( result[0] != FT_ORIENTATION_NONE                     &&
-         ( result[0] == result[1] || result[0] == result[2] ) )
-      return result[0];
-
-    if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )
-      return result[1];
-
-    return FT_ORIENTATION_TRUETYPE;
+    if ( area > 0 )
+      return FT_ORIENTATION_POSTSCRIPT;
+    else if ( area < 0 )
+      return FT_ORIENTATION_TRUETYPE;
+    else
+      return FT_ORIENTATION_NONE;
   }