parent
318f3befc6
commit
b7e18efcd2
4 changed files with 472 additions and 0 deletions
@ -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__ */ |
@ -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 ); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in new issue