adding path stroker component (first steps)

This commit is contained in:
David Turner 2002-06-26 22:05:05 +00:00
parent 318f3befc6
commit b7e18efcd2
4 changed files with 472 additions and 0 deletions

View File

@ -0,0 +1,144 @@
#ifndef __FT_STROKER_H__
#define __FT_STROKER_H__
#include <ft2build.h>
#include FT_OUTLINE_H
FT_BEGIN_HEADER
/**************************************************************
*
* @type: FT_Stroker
*
* @description:
* opaque handler to a path stroker object
*/
typedef struct FT_StrokerRec_* FT_Stroker;
/**************************************************************
*
* @enum: FT_Stroker_LineJoin
*
* @description:
* these values determine how two joining lines are rendered
* in a stroker.
*
* @values:
* FT_STROKER_LINEJOIN_ROUND ::
* used to render rounded line joins. circular arcs are used
* to join two lines smoothly
*
* FT_STROKER_LINEJOIN_BEVEL ::
* used to render beveled line joins; i.e. the two joining lines
* are extended until they intersect
*
* FT_STROKER_LINEJOIN_MITER ::
* same as beveled rendering, except that an additional line
* break is added if the angle between the two joining lines
* is too closed (this is useful to avoid unpleasant spikes
* in beveled rendering).
*/
typedef enum
{
FT_STROKER_LINEJOIN_ROUND = 0,
FT_STROKER_LINEJOIN_BEVEL,
FT_STROKER_LINEJOIN_MITER
} FT_Stroker_LineJoin;
/**************************************************************
*
* @enum: FT_Stroker_LineCap
*
* @description:
* these values determine how the end of opened sub-paths are
* rendered in a stroke
*
* @values:
* FT_STROKER_LINECAP_BUTT ::
* the end of lines is rendered as a full stop on the last
* point itself
*
* FT_STROKER_LINECAP_ROUND ::
* the end of lines is rendered as a half-circle around the
* last point
*
* FT_STROKER_LINEJOIN_MITER ::
* the end of lines is rendered as a square around the
* last point
*/
typedef enum
{
FT_STROKER_LINECAP_BUTT = 0,
FT_STROKER_LINECAP_ROUND,
FT_STROKER_LINECAP_SQUARE
} FT_Stroker_LineCap;
FT_EXPORT( FT_Error )
FT_Stroker_New( FT_Memory memory,
FT_Stroker *astroker );
FT_EXPORT( void )
FT_Stroker_Set( FT_Stroker stroker,
FT_Fixed radius,
FT_Stroker_LineCap line_cap,
FT_Stroker_LineJoin line_join,
FT_Fixed miter_limit );
FT_EXPORT( FT_Error )
FT_Stroker_BeginSubPath( FT_Stroker stroker,
FT_Pos x,
FT_Pos y,
FT_Bool open );
FT_EXPORT( FT_Error )
FT_Stroker_EndSubPath( FT_Stroker stroker );
FT_EXPORT( FT_Error )
FT_Stroker_LineTo( FT_Stroker stroker,
FT_Pos to_x,
FT_Pos to_y );
FT_EXPORT( FT_Error )
FT_Stroker_ConicTo( FT_Stroker stroker,
FT_Pos control_x,
FT_Pos control_y,
FT_Pos to_x,
FT_Pos to_y );
FT_EXPORT( FT_Error )
FT_Stroker_CubicTo( FT_Stroker stroker,
FT_Pos control1_x,
FT_Pos control1_y,
FT_Pos control2_x,
FT_Pos control2_y,
FT_Pos to_x,
FT_Pos to_y );
FT_EXPORT( FT_Error )
FT_Stroker_GetCounts( FT_Stroker stroker,
FT_UInt *anum_points,
FT_UInt *anum_contours );
FT_EXPORT( void )
FT_Stroker_Export( FT_Stroker stroker,
FT_Outliner* outline );
FT_EXPORT( void )
FT_Stroker_Done( FT_Stroker stroker );
FT_EXPORT( FT_Error )
FT_Stroker_ParseOutline( FT_Stroker stroker,
FT_Outline* outline,
FT_Bool opened );
FT_END_HEADER
#endif /* __FT_STROKER_H__ */

View File

@ -173,6 +173,27 @@ FT_BEGIN_HEADER
FT_Fixed y ); FT_Fixed y );
/*************************************************************************/
/* */
/* @function: */
/* FT_Angle_Diff */
/* */
/* @description: */
/* Returns the difference between two angles. The result is always */
/* constrained to the ]-PI..PI] interval */
/* */
/* @input: */
/* angle1 :: first angle */
/* angle2 :: second angle */
/* */
/* @return: */
/* contrainted value of 'value2-value1' */
/* */
FT_EXPORT_DEF( FT_Angle )
FT_Angle_Dif( FT_Angle angle1,
FT_Angle angle2 );
/*************************************************************************/ /*************************************************************************/
/* */ /* */
/* @function: */ /* @function: */

290
src/base/ftstroker.c Normal file
View File

@ -0,0 +1,290 @@
#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 );
}
}

View File

@ -451,4 +451,21 @@
} }
/* documentation is in fttrigon.h */
FT_EXPORT_DEF( FT_Angle )
FT_Angle_Dif( FT_Angle angle1,
FT_Angle angle2 )
{
FT_Angle delta = angle2 - angle1;
delta %= FT_ANGLE_2PI;
if ( delta > FT_ANGLE_PI )
delta -= FT_ANGLE_2PI;
return delta;
}
/* END */ /* END */