shithub: freetype+ttf2subf

ref: b7e18efcd2d6a71ec1a4bdf167f78d707ac91593
dir: /src/base/ftstroker.c/

View raw version
#include <ft2build.h>
#include FT_STROKER_H
#include FT_TRIGONOMETRY_H

 /***************************************************************************/
 /***************************************************************************/
 /*****                                                                 *****/
 /*****                       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  = 
      
      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;
  }


  static FT_Error
  ft_stroke_border_lineto( FT_StrokeBorder  border,
                           FT_Vector*       to )
  {
    FT_Error  error;
    
    FT_ASSERT( border->start >= 0 );
    
    error = ft_stroker_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;
    }
    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_stroker_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;
    }
    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_stroker_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;
    }
    return error;
  }


  static FT_Error
  ft_stroke_border_moveto( FT_StrokeBorder  border,
                           FT_Vector*       to )
  {
    FT_Error  error;
    
    /* close current open path if any ? */
    if ( border->start >= 0 )
      ft_stroke_border_close( border );
    
    border->start = border->num_points;

    return ft_stroke_border_lineto( border, to );
  }
  
 
 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 )
 {
   memory = border->memory;
   
   FT_FREE( border->points );
   FT_FREE( border->tags );
   
   border->num_points = 0;
   border->max_points = 0;
   border->start      = -1;
 }


 /***************************************************************************/
 /***************************************************************************/
 /*****                                                                 *****/
 /*****                           STROKER                               *****/
 /*****                                                                 *****/
 /***************************************************************************/
 /***************************************************************************/

#define  FT_SIDE_TO_ROTATE(s)   (FT_PI2 - (s)*FT_PI)

  typedef struct FT_StrokerRec_
  {
    FT_Angle             angle_in;
    FT_Angle             angle_out;
    FT_Vector            center;
    FT_Bool              first_point;
    FT_Bool              subpath_open;
    FT_Angle             subpath_angle;
    FT_Vector            subpath_start;

    FT_Stroker_LineCap   line_cap;
    FT_Stroker_LineJoin  line_join;
    FT_Fixed             miter_limit;
    FT_Fixed             radius;

    FT_StrokeBorderRec   borders[2];
    FT_Memory            memory;
  
  } FT_StrokerRec;


  FT_EXPORT_DEF( FT_Error )
  FT_Stroker_New( FT_Memory    memory,
                  FT_Stroker  *astroker )
  {
    FT_Error    error;
    FT_Stroker  stroker;
    
    if ( !FT_NEW( stroker ) )
    {
      stroker->memory = memory;
      
      ft_stroke_border_init( &stroker->borders[0], memory );
      ft_stroke_border_init( &stroker->borders[1], memory );
    }
    *astroker = stroker;
    return error;
  }


  FT_EXPORT_DEF( void )
  FT_Stroker_Set( FT_Stroker           stroker,
                  FT_Fixed             radius,
                  FT_Stroker_LineCap   line_cap,
                  FT_Stroker_LineJoin  line_join,
                  FT_Fixed             miter_limit )
  {
    stroker->radius      = radius;
    stroker->line_cap    = line_cap;
    stroker->line_join   = line_join;
    stroker->miter_limit = miter_limit;
    
    ft_stroke_border_reset( &stroker->borders[0] );
    ft_stroke_border_reset( &stroker->borders[1] );
  }


  FT_EXPORT( void )
  FT_Stroker_Done( FT_Stroker  stroker )
  {
    if ( stroker )
    {
      FT_Memory  memory = stroker->memory;
      
      ft_stroke_border_done( &stroker->borders[0] );
      ft_stroke_border_done( &stroker->borders[1] );
      
      stroker->memory = NULL;
      FT_FREE( stroker );
    }
  }