#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. Load more
#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;