adding path stroker component (first steps)
This commit is contained in:
parent
318f3befc6
commit
b7e18efcd2
144
include/freetype/ftstroker.h
Normal file
144
include/freetype/ftstroker.h
Normal 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__ */
|
@ -173,6 +173,27 @@ FT_BEGIN_HEADER
|
||||
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: */
|
||||
|
290
src/base/ftstroker.c
Normal file
290
src/base/ftstroker.c
Normal 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user