tizen 2.3.1 release
[framework/graphics/freetype.git] / src / smooth / ftgrays.c
index 4c0eea5..131ad27 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    A new `perfect' anti-aliasing renderer (body).                       */
 /*                                                                         */
-/*  Copyright 2000-2003, 2005-2012 by                                      */
+/*  Copyright 2000-2003, 2005-2014 by                                      */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -24,8 +24,8 @@
   /*                                                                       */
   /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
   /*                                                                       */
-  /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
-  /*   same directory                                                      */
+  /* - copy `include/ftimage.h' and `src/smooth/ftgrays.h' to the same     */
+  /*   directory                                                           */
   /*                                                                       */
   /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
   /*                                                                       */
 #ifdef _STANDALONE_
 
 
+  /* Auxiliary macros for token concatenation. */
+#define FT_ERR_XCAT( x, y )  x ## y
+#define FT_ERR_CAT( x, y )   FT_ERR_XCAT( x, y )
+
+#define FT_BEGIN_STMNT  do {
+#define FT_END_STMNT    } while ( 0 )
+
+
   /* define this to dump debugging information */
 /* #define FT_DEBUG_LEVEL_TRACE */
 
@@ -154,6 +162,21 @@ typedef ptrdiff_t  FT_PtrDist;
     va_end( ap );
   }
 
+
+  /* empty function useful for setting a breakpoint to catch errors */
+  int
+  FT_Throw( int          error,
+            int          line,
+            const char*  file )
+  {
+    FT_UNUSED( error );
+    FT_UNUSED( line );
+    FT_UNUSED( file );
+
+    return 0;
+  }
+
+
   /* we don't handle tracing levels in stand-alone mode; */
 #ifndef FT_TRACE5
 #define FT_TRACE5( varformat )  FT_Message varformat
@@ -165,11 +188,19 @@ typedef ptrdiff_t  FT_PtrDist;
 #define FT_ERROR( varformat )   FT_Message varformat
 #endif
 
+#define FT_THROW( e )                               \
+          ( FT_Throw( FT_ERR_CAT( ErrRaster, e ),   \
+                      __LINE__,                     \
+                      __FILE__ )                  | \
+            FT_ERR_CAT( ErrRaster, e )            )
+
 #else /* !FT_DEBUG_LEVEL_TRACE */
 
 #define FT_TRACE5( x )  do { } while ( 0 )     /* nothing */
 #define FT_TRACE7( x )  do { } while ( 0 )     /* nothing */
 #define FT_ERROR( x )   do { } while ( 0 )     /* nothing */
+#define FT_THROW( e )   FT_ERR_CAT( ErrRaster_, e )
+
 
 #endif /* !FT_DEBUG_LEVEL_TRACE */
 
@@ -202,6 +233,7 @@ typedef ptrdiff_t  FT_PtrDist;
             raster_done_                                          \
          };
 
+
 #else /* !_STANDALONE_ */
 
 
@@ -215,13 +247,14 @@ typedef ptrdiff_t  FT_PtrDist;
 
 #include "ftspic.h"
 
-#define ErrRaster_Invalid_Mode      Smooth_Err_Cannot_Render_Glyph
-#define ErrRaster_Invalid_Outline   Smooth_Err_Invalid_Outline
+#define Smooth_Err_Invalid_Mode     Smooth_Err_Cannot_Render_Glyph
+#define Smooth_Err_Memory_Overflow  Smooth_Err_Out_Of_Memory
 #define ErrRaster_Memory_Overflow   Smooth_Err_Out_Of_Memory
-#define ErrRaster_Invalid_Argument  Smooth_Err_Invalid_Argument
+
 
 #endif /* !_STANDALONE_ */
 
+
 #ifndef FT_MEM_SET
 #define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
 #endif
@@ -280,6 +313,40 @@ typedef ptrdiff_t  FT_PtrDist;
 #endif
 
 
+  /* Compute `dividend / divisor' and return both its quotient and     */
+  /* remainder, cast to a specific type.  This macro also ensures that */
+  /* the remainder is always positive.                                 */
+#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
+  FT_BEGIN_STMNT                                                   \
+    (quotient)  = (type)( (dividend) / (divisor) );                \
+    (remainder) = (type)( (dividend) % (divisor) );                \
+    if ( (remainder) < 0 )                                         \
+    {                                                              \
+      (quotient)--;                                                \
+      (remainder) += (type)(divisor);                              \
+    }                                                              \
+  FT_END_STMNT
+
+#ifdef  __arm__
+  /* Work around a bug specific to GCC which make the compiler fail to */
+  /* optimize a division and modulo operation on the same parameters   */
+  /* into a single call to `__aeabi_idivmod'.  See                     */
+  /*                                                                   */
+  /*  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721                */
+#undef FT_DIV_MOD
+#define FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
+  FT_BEGIN_STMNT                                                   \
+    (quotient)  = (type)( (dividend) / (divisor) );                \
+    (remainder) = (type)( (dividend) - (quotient) * (divisor) );   \
+    if ( (remainder) < 0 )                                         \
+    {                                                              \
+      (quotient)--;                                                \
+      (remainder) += (type)(divisor);                              \
+    }                                                              \
+  FT_END_STMNT
+#endif /* __arm__ */
+
+
   /*************************************************************************/
   /*                                                                       */
   /*   TYPE DEFINITIONS                                                    */
@@ -312,7 +379,7 @@ typedef ptrdiff_t  FT_PtrDist;
 #endif /* PIXEL_BITS >= 8 */
 
 
-  /* maximal number of gray spans in a call to the span callback */
+  /* maximum number of gray spans in a call to the span callback */
 #define FT_MAX_GRAY_SPANS  32
 
 
@@ -328,8 +395,18 @@ typedef ptrdiff_t  FT_PtrDist;
   } TCell;
 
 
+#if defined( _MSC_VER )      /* Visual C++ (and Intel C++) */
+  /* We disable the warning `structure was padded due to   */
+  /* __declspec(align())' in order to compile cleanly with */
+  /* the maximum level of warnings.                        */
+#pragma warning( push )
+#pragma warning( disable : 4324 )
+#endif /* _MSC_VER */
+
   typedef struct  gray_TWorker_
   {
+    ft_jmp_buf  jump_buffer;
+
     TCoord  ex, ey;
     TPos    min_ex, max_ex;
     TPos    min_ey, max_ey;
@@ -365,8 +442,6 @@ typedef ptrdiff_t  FT_PtrDist;
     int  band_size;
     int  band_shoot;
 
-    ft_jmp_buf  jump_buffer;
-
     void*       buffer;
     long        buffer_size;
 
@@ -375,6 +450,10 @@ typedef ptrdiff_t  FT_PtrDist;
 
   } gray_TWorker, *gray_PWorker;
 
+#if defined( _MSC_VER )
+#pragma warning( pop )
+#endif
+
 
 #ifndef FT_STATIC_RASTER
 #define ras  (*worker)
@@ -506,7 +585,7 @@ typedef ptrdiff_t  FT_PtrDist;
   static void
   gray_record_cell( RAS_ARG )
   {
-    if ( !ras.invalid && ( ras.area | ras.cover ) )
+    if ( ras.area | ras.cover )
     {
       PCell  cell = gray_find_cell( RAS_VAR );
 
@@ -555,10 +634,10 @@ typedef ptrdiff_t  FT_PtrDist;
 
       ras.area  = 0;
       ras.cover = 0;
+      ras.ex    = ex;
+      ras.ey    = ey;
     }
 
-    ras.ex      = ex;
-    ras.ey      = ey;
     ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
                               ex >= ras.count_ex           );
   }
@@ -600,7 +679,7 @@ typedef ptrdiff_t  FT_PtrDist;
                                  TPos    x2,
                                  TCoord  y2 )
   {
-    TCoord  ex1, ex2, fx1, fx2, delta, mod, lift, rem;
+    TCoord  ex1, ex2, fx1, fx2, delta, mod;
     long    p, first, dx;
     int     incr;
 
@@ -644,13 +723,7 @@ typedef ptrdiff_t  FT_PtrDist;
       dx    = -dx;
     }
 
-    delta = (TCoord)( p / dx );
-    mod   = (TCoord)( p % dx );
-    if ( mod < 0 )
-    {
-      delta--;
-      mod += (TCoord)dx;
-    }
+    FT_DIV_MOD( TCoord, p, dx, delta, mod );
 
     ras.area  += (TArea)(( fx1 + first ) * delta);
     ras.cover += delta;
@@ -661,14 +734,11 @@ typedef ptrdiff_t  FT_PtrDist;
 
     if ( ex1 != ex2 )
     {
-      p    = ONE_PIXEL * ( y2 - y1 + delta );
-      lift = (TCoord)( p / dx );
-      rem  = (TCoord)( p % dx );
-      if ( rem < 0 )
-      {
-        lift--;
-        rem += (TCoord)dx;
-      }
+      TCoord  lift, rem;
+
+
+      p = ONE_PIXEL * ( y2 - y1 + delta );
+      FT_DIV_MOD( TCoord, p, dx, lift, rem );
 
       mod -= (int)dx;
 
@@ -718,9 +788,6 @@ typedef ptrdiff_t  FT_PtrDist;
     dx = to_x - ras.x;
     dy = to_y - ras.y;
 
-    /* XXX: we should do something about the trivial case where dx == 0, */
-    /*      as it happens very often!                                    */
-
     /* perform vertical clipping */
     {
       TCoord  min, max;
@@ -799,13 +866,7 @@ typedef ptrdiff_t  FT_PtrDist;
       dy    = -dy;
     }
 
-    delta = (int)( p / dy );
-    mod   = (int)( p % dy );
-    if ( mod < 0 )
-    {
-      delta--;
-      mod += (TCoord)dy;
-    }
+    FT_DIV_MOD( int, p, dy, delta, mod );
 
     x = ras.x + delta;
     gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
@@ -816,13 +877,7 @@ typedef ptrdiff_t  FT_PtrDist;
     if ( ey1 != ey2 )
     {
       p     = ONE_PIXEL * dx;
-      lift  = (int)( p / dy );
-      rem   = (int)( p % dy );
-      if ( rem < 0 )
-      {
-        lift--;
-        rem += (int)dy;
-      }
+      FT_DIV_MOD( int, p, dy, lift, rem );
       mod -= (int)dy;
 
       while ( ey1 != ey2 )
@@ -1036,37 +1091,10 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
         /* dx and dy are x and y components of the P0-P3 chord vector. */
-        dx = arc[3].x - arc[0].x;
-        dy = arc[3].y - arc[0].y;
-
-        /* L is an (under)estimate of the Euclidean distance P0-P3.       */
-        /*                                                                */
-        /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated   */
-        /* with least maximum error by                                    */
-        /*                                                                */
-        /*   r_upperbound = dx + (sqrt(2) - 1) * dy  ,                    */
-        /*                                                                */
-        /* where sqrt(2) - 1 can be (over)estimated by 107/256, giving an */
-        /* error of no more than 8.4%.                                    */
-        /*                                                                */
-        /* Similarly, some elementary calculus shows that r can be        */
-        /* underestimated with least maximum error by                     */
-        /*                                                                */
-        /*   r_lowerbound = sqrt(2 + sqrt(2)) / 2 * dx                    */
-        /*                  + sqrt(2 - sqrt(2)) / 2 * dy  .               */
-        /*                                                                */
-        /* 236/256 and 97/256 are (under)estimates of the two algebraic   */
-        /* numbers, giving an error of no more than 8.1%.                 */
-
-        dx_ = FT_ABS( dx );
-        dy_ = FT_ABS( dy );
-
-        /* This is the same as                     */
-        /*                                         */
-        /*   L = ( 236 * FT_MAX( dx_, dy_ )        */
-        /*       + 97 * FT_MIN( dx_, dy_ ) ) >> 8; */
-        L = ( dx_ > dy_ ? 236 * dx_ +  97 * dy_
-                        :  97 * dx_ + 236 * dy_ ) >> 8;
+        dx = dx_ = arc[3].x - arc[0].x;
+        dy = dy_ = arc[3].y - arc[0].y;
+
+        L = FT_HYPOT( dx_, dy_ );
 
         /* Avoid possible arithmetic overflow below by splitting. */
         if ( L > 32767 )
@@ -1091,11 +1119,11 @@ typedef ptrdiff_t  FT_PtrDist;
         if ( s > s_limit )
           goto Split;
 
-        /* If P1 or P2 is outside P0-P3, split the curve. */
-        if ( dy * dy1 + dx * dx1 < 0                                     ||
-             dy * dy2 + dx * dx2 < 0                                     ||
-             dy * (arc[3].y - arc[1].y) + dx * (arc[3].x - arc[1].x) < 0 ||
-             dy * (arc[3].y - arc[2].y) + dx * (arc[3].x - arc[2].x) < 0 )
+        /* Split super curvy segments where the off points are so far
+           from the chord that the angles P0-P1-P3 or P0-P2-P3 become
+           acute as detected by appropriate dot products. */
+        if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 ||
+             dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 )
           goto Split;
 
         /* No reason to split. */
@@ -1126,7 +1154,8 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
     /* record current cell, if any */
-    gray_record_cell( RAS_VAR );
+    if ( !ras.invalid )
+      gray_record_cell( RAS_VAR );
 
     /* start to a new position */
     x = UPSCALE( to->x );
@@ -1227,9 +1256,7 @@ typedef ptrdiff_t  FT_PtrDist;
                        TPos    area,
                        TCoord  acount )
   {
-    FT_Span*  span;
-    int       count;
-    int       coverage;
+    int  coverage;
 
 
     /* compute the coverage line's coverage, depending on the    */
@@ -1271,6 +1298,10 @@ typedef ptrdiff_t  FT_PtrDist;
 
     if ( coverage )
     {
+      FT_Span*  span;
+      int       count;
+
+
       /* see whether we can add this span to the current list */
       count = ras.num_gray_spans;
       span  = ras.gray_spans + count - 1;
@@ -1309,7 +1340,6 @@ typedef ptrdiff_t  FT_PtrDist;
         ras.num_gray_spans = 0;
         ras.span_y         = (int)y;
 
-        count = 0;
         span  = ras.gray_spans;
       }
       else
@@ -1400,7 +1430,26 @@ typedef ptrdiff_t  FT_PtrDist;
       ras.render_span( ras.span_y, ras.num_gray_spans,
                        ras.gray_spans, ras.render_span_data );
 
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+    if ( ras.num_gray_spans > 0 )
+    {
+      FT_Span*  span;
+      int       n;
+
+
+      FT_TRACE7(( "y = %3d ", ras.span_y ));
+      span = ras.gray_spans;
+      for ( n = 0; n < ras.num_gray_spans; n++, span++ )
+        FT_TRACE7(( "[%d..%d]:%02x ",
+                    span->x, span->x + span->len - 1, span->coverage ));
+      FT_TRACE7(( "\n" ));
+    }
+
     FT_TRACE7(( "gray_sweep: end\n" ));
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
   }
 
 
@@ -1466,8 +1515,11 @@ typedef ptrdiff_t  FT_PtrDist;
     TPos  delta;
 
 
-    if ( !outline || !func_interface )
-      return ErrRaster_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;
@@ -1680,7 +1732,7 @@ typedef ptrdiff_t  FT_PtrDist;
     return error;
 
   Invalid_Outline:
-    return ErrRaster_Invalid_Outline;
+    return FT_THROW( Invalid_Outline );
   }
 
 #endif /* _STANDALONE_ */
@@ -1715,10 +1767,11 @@ typedef ptrdiff_t  FT_PtrDist;
     if ( ft_setjmp( ras.jump_buffer ) == 0 )
     {
       error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
-      gray_record_cell( RAS_VAR );
+      if ( !ras.invalid )
+        gray_record_cell( RAS_VAR );
     }
     else
-      error = ErrRaster_Memory_Overflow;
+      error = FT_THROW( Memory_Overflow );
 
     return error;
   }
@@ -1871,21 +1924,21 @@ typedef ptrdiff_t  FT_PtrDist;
 
 
     if ( !raster || !raster->buffer || !raster->buffer_size )
-      return ErrRaster_Invalid_Argument;
+      return FT_THROW( Invalid_Argument );
 
     if ( !outline )
-      return ErrRaster_Invalid_Outline;
+      return FT_THROW( Invalid_Outline );
 
     /* return immediately if the outline is empty */
     if ( outline->n_points == 0 || outline->n_contours <= 0 )
       return 0;
 
     if ( !outline->contours || !outline->points )
-      return ErrRaster_Invalid_Outline;
+      return FT_THROW( Invalid_Outline );
 
     if ( outline->n_points !=
            outline->contours[outline->n_contours - 1] + 1 )
-      return ErrRaster_Invalid_Outline;
+      return FT_THROW( Invalid_Outline );
 
     worker = raster->worker;
 
@@ -1893,19 +1946,19 @@ typedef ptrdiff_t  FT_PtrDist;
     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
     {
       if ( !target_map )
-        return ErrRaster_Invalid_Argument;
+        return FT_THROW( Invalid_Argument );
 
       /* nothing to do */
       if ( !target_map->width || !target_map->rows )
         return 0;
 
       if ( !target_map->buffer )
-        return ErrRaster_Invalid_Argument;
+        return FT_THROW( Invalid_Argument );
     }
 
     /* this version does not support monochrome rendering */
     if ( !( params->flags & FT_RASTER_FLAG_AA ) )
-      return ErrRaster_Invalid_Mode;
+      return FT_THROW( Invalid_Mode );
 
     /* compute clipping box */
     if ( !( params->flags & FT_RASTER_FLAG_DIRECT ) )
@@ -2047,12 +2100,26 @@ typedef ptrdiff_t  FT_PtrDist;
   }
 
 
+  static int
+  gray_raster_set_mode( FT_Raster      raster,
+                        unsigned long  mode,
+                        void*          args )
+  {
+    FT_UNUSED( raster );
+    FT_UNUSED( mode );
+    FT_UNUSED( args );
+
+
+    return 0; /* nothing to do */
+  }
+
+
   FT_DEFINE_RASTER_FUNCS(ft_grays_raster,
     FT_GLYPH_FORMAT_OUTLINE,
 
     (FT_Raster_New_Func)     gray_raster_new,
     (FT_Raster_Reset_Func)   gray_raster_reset,
-    (FT_Raster_Set_Mode_Func)0,
+    (FT_Raster_Set_Mode_Func)gray_raster_set_mode,
     (FT_Raster_Render_Func)  gray_raster_render,
     (FT_Raster_Done_Func)    gray_raster_done
   )