Charles.Forsyth20060303a828770d19 years agoHistory
1364 lines · 35.8 KB · C
RawDownload
#include <ft2build.h>#include FT_STROKER_H#include FT_TRIGONOMETRY_H#include FT_INTERNAL_MEMORY_H#include FT_INTERNAL_DEBUG_H  /***************************************************************************/ /***************************************************************************/ /*****                                                                 *****/ /*****                       BEZIER COMPUTATIONS                       *****/ /*****                                                                 *****/ /***************************************************************************/ /***************************************************************************/ #define FT_SMALL_CONIC_THRESHOLD   (FT_ANGLE_PI/6)#define FT_SMALL_CUBIC_THRESHOLD   (FT_ANGLE_PI/6)#define FT_EPSILON  2 #define FT_IS_SMALL(x)  ((x) > -FT_EPSILON && (x) < FT_EPSILON)   static FT_Pos  ft_pos_abs( FT_Pos  x )  {    return  x >= 0 ? x : -x ;  }   static void  ft_conic_split( FT_Vector*  base )  {    FT_Pos  a, b;      base[4].x = base[2].x;    b = base[1].x;    a = base[3].x = ( base[2].x + b )/2;    b = base[1].x = ( base[0].x + b )/2;    base[2].x = ( a + b )/2;     base[4].y = base[2].y;    b = base[1].y;    a = base[3].y = ( base[2].y + b )/2;    b = base[1].y = ( base[0].y + b )/2;    base[2].y = ( a + b )/2;  }    static FT_Bool  ft_conic_is_small_enough( FT_Vector*  base,                            FT_Angle   *angle_in,                            FT_Angle   *angle_out )  {    FT_Vector  d1, d2;    FT_Angle   theta;    FT_Int     close1, close2;     d1.x = base[1].x - base[2].x;    d1.y = base[1].y - base[2].y;    d2.x = base[0].x - base[1].x;    d2.y = base[0].y - base[1].y;     close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);    close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);     if (close1)    {      if (close2)        *angle_in = *angle_out = 0;      else        *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );    }    else if (close2)    {      *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );    }    else    {      *angle_in  = FT_Atan2( d1.x, d1.y );      *angle_out = FT_Atan2( d2.x, d2.y );    }     theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );     return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );  }    static void  ft_cubic_split( FT_Vector*  base )  {    FT_Pos  a, b, c, d;      base[6].x = base[3].x;    c = base[1].x;    d = base[2].x;    base[1].x = a = ( base[0].x + c )/2;    base[5].x = b = ( base[3].x + d )/2;    c = ( c + d )/2;    base[2].x = a = ( a + c )/2;    base[4].x = b = ( b + c )/2;    base[3].x = ( a + b )/2;     base[6].y = base[3].y;    c = base[1].y;    d = base[2].y;    base[1].y = a = ( base[0].y + c )/2;    base[5].y = b = ( base[3].y + d )/2;    c = ( c + d )/2;    base[2].y = a = ( a + c )/2;    base[4].y = b = ( b + c )/2;    base[3].y = ( a + b )/2;  }    static FT_Bool  ft_cubic_is_small_enough( FT_Vector*  base,                            FT_Angle   *angle_in,                            FT_Angle   *angle_mid,                            FT_Angle   *angle_out )  {    FT_Vector  d1, d2, d3;    FT_Angle   theta1, theta2;    FT_Int     close1, close2, close3;     d1.x = base[2].x - base[3].x;    d1.y = base[2].y - base[3].y;    d2.x = base[1].x - base[2].x;    d2.y = base[1].y - base[2].y;    d3.x = base[0].x - base[1].x;    d3.y = base[0].y - base[1].y;     close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);    close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);    close3 = FT_IS_SMALL(d3.x) && FT_IS_SMALL(d3.y);     if (close1 || close3)    {      if (close2)      {        /* basically a point */        *angle_in = *angle_out = *angle_mid = 0;      }      else if (close1)      {        *angle_in  = *angle_mid = FT_Atan2( d2.x, d2.y );        *angle_out = FT_Atan2( d3.x, d3.y );      }      else  /* close2 */      {        *angle_in  = FT_Atan2( d1.x, d1.y );        *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );      }    }    else if (close2)    {      *angle_in  = *angle_mid = FT_Atan2( d1.x, d1.y );      *angle_out = FT_Atan2( d3.x, d3.y );    }    else    {      *angle_in  = FT_Atan2( d1.x, d1.y );      *angle_mid = FT_Atan2( d2.x, d2.y );      *angle_out = FT_Atan2( d3.x, d3.y );    }    theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in,  *angle_mid ) );    theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );     return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&                    theta2 < FT_SMALL_CUBIC_THRESHOLD );  }    /***************************************************************************/ /***************************************************************************/ /*****                                                                 *****/ /*****                       STROKE BORDERS                            *****/ /*****                                                                 *****/ /***************************************************************************/ /***************************************************************************/   typedef enum  {    FT_STROKE_TAG_ON    = 1,   /* on-curve point  */    FT_STROKE_TAG_CUBIC = 2,   /* cubic off-point */    FT_STROKE_TAG_BEGIN = 4,   /* sub-path start  */    FT_STROKE_TAG_END   = 8    /* sub-path end    */   } FT_StrokeTags;    typedef struct FT_StrokeBorderRec_  {    FT_UInt     num_points;    FT_UInt     max_points;    FT_Vector*  points;    FT_Byte*    tags;    FT_Bool     movable;    FT_Int      start;    /* index of current sub-path start point */    FT_Memory   memory;   } FT_StrokeBorderRec, *FT_StrokeBorder;    static FT_Error  ft_stroke_border_grow( FT_StrokeBorder  border,                         FT_UInt          new_points )  {    FT_UInt   old_max = border->max_points;    FT_UInt   new_max = border->num_points + new_points;    FT_Error  error   = 0;     if ( new_max > old_max )    {      FT_UInt    cur_max = old_max;      FT_Memory  memory  = border->memory;       while ( cur_max < new_max )        cur_max += (cur_max >> 1) + 16;       if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||           FT_RENEW_ARRAY( border->tags,   old_max, cur_max ) )        goto Exit;       border->max_points = cur_max;    }  Exit:    return error;  }   static void  ft_stroke_border_close( FT_StrokeBorder  border )  {    FT_ASSERT( border->start >= 0 );     border->tags[ border->start        ] |= FT_STROKE_TAG_BEGIN;    border->tags[ border->num_points-1 ] |= FT_STROKE_TAG_END;     border->start   = -1;    border->movable = 0;  }    static FT_Error  ft_stroke_border_lineto( FT_StrokeBorder  border,                           FT_Vector*       to,                           FT_Bool          movable )  {    FT_Error  error = 0;     FT_ASSERT( border->start >= 0 );     if ( border->movable )    {      /* move last point */      border->points[ border->num_points-1 ] = *to;    }    else    {      /* add one point */      error = ft_stroke_border_grow( border, 1 );      if (!error)      {        FT_Vector*  vec = border->points + border->num_points;        FT_Byte*    tag = border->tags   + border->num_points;         vec[0] = *to;        tag[0] = FT_STROKE_TAG_ON;         border->num_points += 1;      }    }    border->movable = movable;    return error;  }    static FT_Error  ft_stroke_border_conicto( FT_StrokeBorder  border,                            FT_Vector*       control,                            FT_Vector*       to )  {    FT_Error  error;     FT_ASSERT( border->start >= 0 );     error = ft_stroke_border_grow( border, 2 );    if (!error)    {      FT_Vector*  vec = border->points + border->num_points;      FT_Byte*    tag = border->tags   + border->num_points;       vec[0] = *control;      vec[1] = *to;       tag[0] = 0;      tag[1] = FT_STROKE_TAG_ON;       border->num_points += 2;    }    border->movable = 0;    return error;  }    static FT_Error  ft_stroke_border_cubicto( FT_StrokeBorder  border,                            FT_Vector*       control1,                            FT_Vector*       control2,                            FT_Vector*       to )  {    FT_Error  error;     FT_ASSERT( border->start >= 0 );     error = ft_stroke_border_grow( border, 3 );    if (!error)    {      FT_Vector*  vec = border->points + border->num_points;      FT_Byte*    tag = border->tags   + border->num_points;       vec[0] = *control1;      vec[1] = *control2;      vec[2] = *to;       tag[0] = FT_STROKE_TAG_CUBIC;      tag[1] = FT_STROKE_TAG_CUBIC;      tag[2] = FT_STROKE_TAG_ON;       border->num_points += 3;    }    border->movable = 0;    return error;  }  #define  FT_ARC_CUBIC_ANGLE  (FT_ANGLE_PI/2)    static FT_Error  ft_stroke_border_arcto( FT_StrokeBorder  border,                          FT_Vector*       center,                          FT_Fixed         radius,                          FT_Angle         angle_start,                          FT_Angle         angle_diff )  {    FT_Angle   total, angle, step, rotate, next, theta;    FT_Vector  a, b, a2, b2;    FT_Fixed   length;    FT_Error   error = 0;     /* compute start point */    FT_Vector_From_Polar( &a, radius, angle_start );    a.x += center->x;    a.y += center->y;     total  = angle_diff;    angle  = angle_start;    rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;     while (total != 0)    {      step = total;      if ( step > FT_ARC_CUBIC_ANGLE )        step   = FT_ARC_CUBIC_ANGLE;       else if ( step < -FT_ARC_CUBIC_ANGLE )        step = -FT_ARC_CUBIC_ANGLE;       next  = angle + step;      theta = step;      if ( theta < 0 )        theta = -theta;       theta >>= 1;       /* compute end point */      FT_Vector_From_Polar( &b, radius, next );      b.x += center->x;      b.y += center->y;       /* compute first and second control points */      length = FT_MulDiv( radius, FT_Sin(theta)*4,                          (0x10000L + FT_Cos(theta))*3 );       FT_Vector_From_Polar( &a2, length, angle + rotate );      a2.x += a.x;      a2.y += a.y;       FT_Vector_From_Polar( &b2, length, next - rotate );      b2.x += b.x;      b2.y += b.y;       /* add cubic arc */      error = ft_stroke_border_cubicto( border, &a2, &b2, &b );      if (error) break;       /* process the rest of the arc ?? */      a      = b;      total -= step;      angle  = next;    }    return error;  }    static FT_Error  ft_stroke_border_moveto( FT_StrokeBorder  border,                           FT_Vector*       to )  {    /* close current open path if any ? */    if ( border->start >= 0 )      ft_stroke_border_close( border );     border->start   = border->num_points;    border->movable = 0;     return ft_stroke_border_lineto( border, to, 0 );  }   static void ft_stroke_border_init( FT_StrokeBorder  border,                        FT_Memory        memory ) {   border->memory = memory;   border->points = NULL;   border->tags   = NULL;    border->num_points = 0;   border->max_points = 0;   border->start      = -1; }   static void ft_stroke_border_reset( FT_StrokeBorder  border ) {   border->num_points = 0;   border->start      = -1; }   static void ft_stroke_border_done( FT_StrokeBorder  border ) {   FT_Memory  memory = border->memory;    FT_FREE( border->points );   FT_FREE( border->tags );    border->num_points = 0;   border->max_points = 0;   border->start      = -1; }   static FT_Error ft_stroke_border_get_counts( FT_StrokeBorder  border,                              FT_UInt         *anum_points,                              FT_UInt         *anum_contours ) {   FT_Error  error        = 0;   FT_UInt   num_points   = 0;   FT_UInt   num_contours = 0;    FT_UInt     count      = border->num_points;   FT_Vector*  point      = border->points;   FT_Byte*    tags       = border->tags;   FT_Int      in_contour = 0;    for ( ; count > 0; count--, point++, tags++ )   {     if ( tags[0] & FT_STROKE_TAG_BEGIN )     {       if ( in_contour != 0 )         goto Fail;        in_contour = 1;     }     else if ( in_contour == 0 )       goto Fail;      if ( tags[0] & FT_STROKE_TAG_END )     {       if ( in_contour == 0 )         goto Fail;        in_contour = 0;       num_contours++;     }   }   if ( in_contour != 0 )     goto Fail;  Exit:   *anum_points   = num_points;   *anum_contours = num_contours;   return error; 

Lines 1–500 of 1364.