📄 ftstroke.c
字号:
else /* this is a bevel (intersection) */
{
FT_Fixed length;
FT_Vector delta;
length = FT_DivFix( stroker->radius, thcos );
FT_Vector_From_Polar( &delta, length, phi );
delta.x += stroker->center.x;
delta.y += stroker->center.y;
error = ft_stroke_border_lineto( border, &delta, 0 );
if (error) goto Exit;
/* now add end point */
FT_Vector_From_Polar( &delta, stroker->radius,
stroker->angle_out + rotate );
delta.x += stroker->center.x;
delta.y += stroker->center.y;
error = ft_stroke_border_lineto( border, &delta, 1 );
}
}
Exit:
return error;
}
static FT_Error
ft_stroker_process_corner( FT_Stroker stroker )
{
FT_Error error = 0;
FT_Angle turn;
FT_Int inside_side;
turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
/* no specific corner processing is required if the turn is 0 */
if ( turn == 0 )
goto Exit;
/* when we turn to the right, the inside side is 0 */
inside_side = 0;
/* otherwise, the inside side is 1 */
if ( turn < 0 )
inside_side = 1;
/* process the inside side */
error = ft_stroker_inside( stroker, inside_side );
if ( error )
goto Exit;
/* process the outside side */
error = ft_stroker_outside( stroker, 1 - inside_side );
Exit:
return error;
}
/* add two points to the left and right borders corresponding to the */
/* start of the subpath.. */
static FT_Error
ft_stroker_subpath_start( FT_Stroker stroker,
FT_Angle start_angle )
{
FT_Vector delta;
FT_Vector point;
FT_Error error;
FT_StrokeBorder border;
FT_Vector_From_Polar( &delta, stroker->radius,
start_angle + FT_ANGLE_PI2 );
point.x = stroker->center.x + delta.x;
point.y = stroker->center.y + delta.y;
border = stroker->borders;
error = ft_stroke_border_moveto( border, &point );
if ( error )
goto Exit;
point.x = stroker->center.x - delta.x;
point.y = stroker->center.y - delta.y;
border++;
error = ft_stroke_border_moveto( border, &point );
/* save angle for last cap */
stroker->subpath_angle = start_angle;
stroker->first_point = 0;
Exit:
return error;
}
/* documentation is in ftstroke.h */
FT_EXPORT_DEF( FT_Error )
FT_Stroker_LineTo( FT_Stroker stroker,
FT_Vector* to )
{
FT_Error error = 0;
FT_StrokeBorder border;
FT_Vector delta;
FT_Angle angle;
FT_Int side;
delta.x = to->x - stroker->center.x;
delta.y = to->y - stroker->center.y;
angle = FT_Atan2( delta.x, delta.y );
FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
/* process corner if necessary */
if ( stroker->first_point )
{
/* This is the first segment of a subpath. We need to */
/* add a point to each border at their respective starting */
/* point locations. */
error = ft_stroker_subpath_start( stroker, angle );
if ( error )
goto Exit;
}
else
{
/* process the current corner */
stroker->angle_out = angle;
error = ft_stroker_process_corner( stroker );
if ( error )
goto Exit;
}
/* now add a line segment to both the "inside" and "outside" paths */
for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
{
FT_Vector point;
point.x = to->x + delta.x;
point.y = to->y + delta.y;
error = ft_stroke_border_lineto( border, &point, 1 );
if ( error )
goto Exit;
delta.x = -delta.x;
delta.y = -delta.y;
}
stroker->angle_in = angle;
stroker->center = *to;
Exit:
return error;
}
/* documentation is in ftstroke.h */
FT_EXPORT_DEF( FT_Error )
FT_Stroker_ConicTo( FT_Stroker stroker,
FT_Vector* control,
FT_Vector* to )
{
FT_Error error = 0;
FT_Vector bez_stack[34];
FT_Vector* arc;
FT_Vector* limit = bez_stack + 30;
FT_Angle start_angle;
FT_Bool first_arc = 1;
arc = bez_stack;
arc[0] = *to;
arc[1] = *control;
arc[2] = stroker->center;
while ( arc >= bez_stack )
{
FT_Angle angle_in, angle_out;
angle_in = angle_out = 0; /* remove compiler warnings */
if ( arc < limit &&
!ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
{
ft_conic_split( arc );
arc += 2;
continue;
}
if ( first_arc )
{
first_arc = 0;
start_angle = angle_in;
/* process corner if necessary */
if ( stroker->first_point )
error = ft_stroker_subpath_start( stroker, start_angle );
else
{
stroker->angle_out = start_angle;
error = ft_stroker_process_corner( stroker );
}
}
/* the arc's angle is small enough; we can add it directly to each */
/* border */
{
FT_Vector ctrl, end;
FT_Angle theta, phi, rotate;
FT_Fixed length;
FT_Int side;
theta = FT_Angle_Diff( angle_in, angle_out ) / 2;
phi = angle_in + theta;
length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
for ( side = 0; side <= 1; side++ )
{
rotate = FT_SIDE_TO_ROTATE( side );
/* compute control point */
FT_Vector_From_Polar( &ctrl, length, phi + rotate );
ctrl.x += arc[1].x;
ctrl.y += arc[1].y;
/* compute end point */
FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
end.x += arc[0].x;
end.y += arc[0].y;
error = ft_stroke_border_conicto( stroker->borders + side,
&ctrl, &end );
if ( error )
goto Exit;
}
}
arc -= 2;
if ( arc < bez_stack )
stroker->angle_in = angle_out;
}
stroker->center = *to;
Exit:
return error;
}
/* documentation is in ftstroke.h */
FT_EXPORT_DEF( FT_Error )
FT_Stroker_CubicTo( FT_Stroker stroker,
FT_Vector* control1,
FT_Vector* control2,
FT_Vector* to )
{
FT_Error error = 0;
FT_Vector bez_stack[37];
FT_Vector* arc;
FT_Vector* limit = bez_stack + 32;
FT_Angle start_angle;
FT_Bool first_arc = 1;
arc = bez_stack;
arc[0] = *to;
arc[1] = *control2;
arc[2] = *control1;
arc[3] = stroker->center;
while ( arc >= bez_stack )
{
FT_Angle angle_in, angle_mid, angle_out;
/* remove compiler warnings */
angle_in = angle_out = angle_mid = 0;
if ( arc < limit &&
!ft_cubic_is_small_enough( arc, &angle_in,
&angle_mid, &angle_out ) )
{
ft_cubic_split( arc );
arc += 3;
continue;
}
if ( first_arc )
{
first_arc = 0;
/* process corner if necessary */
start_angle = angle_in;
if ( stroker->first_point )
error = ft_stroker_subpath_start( stroker, start_angle );
else
{
stroker->angle_out = start_angle;
error = ft_stroker_process_corner( stroker );
}
if ( error )
goto Exit;
}
/* the arc's angle is small enough; we can add it directly to each */
/* border */
{
FT_Vector ctrl1, ctrl2, end;
FT_Angle theta1, phi1, theta2, phi2, rotate;
FT_Fixed length1, length2;
FT_Int side;
theta1 = ft_pos_abs( angle_mid - angle_in ) / 2;
theta2 = ft_pos_abs( angle_out - angle_mid ) / 2;
phi1 = (angle_mid + angle_in ) / 2;
phi2 = (angle_mid + angle_out ) / 2;
length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
for ( side = 0; side <= 1; side++ )
{
rotate = FT_SIDE_TO_ROTATE( side );
/* compute control points */
FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
ctrl1.x += arc[2].x;
ctrl1.y += arc[2].y;
FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
ctrl2.x += arc[1].x;
ctrl2.y += arc[1].y;
/* compute end point */
FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
end.x += arc[0].x;
end.y += arc[0].y;
error = ft_stroke_border_cubicto( stroker->borders + side,
&ctrl1, &ctrl2, &end );
if ( error )
goto Exit;
}
}
arc -= 3;
if ( arc < bez_stack )
stroker->angle_in = angle_out;
}
stroker->center = *to;
Exit:
return error;
}
/* documentation is in ftstroke.h */
FT_EXPORT_DEF( FT_Error )
FT_Stroker_BeginSubPath( FT_Stroker stroker,
FT_Vector* to,
FT_Bool open )
{
/* We cannot process the first point, because there is not enough */
/* information regarding its corner/cap. The latter will be processed */
/* in the "end_subpath" routine. */
/* */
stroker->first_point = 1;
stroker->center = *to;
stroker->subpath_open = open;
/* record the subpath start point index for each border */
stroker->subpath_start = *to;
return 0;
}
static FT_Error
ft_stroker_add_reverse_left( FT_Stroker stroker,
FT_Bool open )
{
FT_StrokeBorder right = stroker->borders + 0;
FT_StrokeBorder left = stroker->borders + 1;
FT_Int new_points;
FT_Error error = 0;
FT_ASSERT( left->start >= 0 );
new_points = left->num_points - left->start;
if ( new_points > 0 )
{
error = ft_stroke_border_grow( right, (FT_UInt)new_points );
if ( error )
goto Exit;
{
FT_Vector* dst_point = right->points + right->num_points;
FT_Byte* dst_tag = right->tags + right->num_points;
FT_Vector* src_point = left->points + left->num_points - 1;
FT_Byte* src_tag = left->tags + left->num_points - 1;
while ( src_point >= left->points + left->start )
{
*dst_point = *src_point;
*dst_tag = *src_tag;
if ( open )
dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END;
else
{
FT_Byte ttag = (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
/* switch begin/end tags if necessary */
if ( ttag == FT_STROKE_TAG_BEGIN ||
ttag == FT_STROKE_TAG_END )
dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END;
}
src_point--;
src_tag--;
dst_point++;
dst_tag++;
}
}
left->num_points = left->start;
right->num_points += new_points;
right->movable = 0;
left->movable = 0;
}
Exit:
return error;
}
/* documentation is in ftstroke.h */
/* there's a lot of magic in this function! */
FT_EXPORT_DEF( FT_Error )
FT_Stroker_EndSubPath( FT_Stroker stroker )
{
FT_Error error = 0;
if ( stroker->subpath_open )
{
FT_StrokeBorder right = stroker->borders;
/* All right, this is an opened path, we need to add a cap between */
/* right & left, add the reverse of left, then add a final cap */
/* between left & right. */
error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
if ( error )
goto Exit;
/* add reversed points from "left" to "right" */
error = ft_stroker_add_reverse_left( stroker, 1 );
if ( error )
goto Exit;
/* now add the final cap */
stroker->center = stroker->subpath_start;
error = ft_stroker_cap( stroker,
stroker->subpath_angle + FT_ANGLE_PI, 0 );
if ( error )
goto Exit;
/* Now end the right subpath accordingly. The left one is */
/* rewind and doesn't need further processing. */
ft_stroke_border_close( right, 0 );
}
else
{
FT_Angle turn;
FT_Int inside_side;
/* close the path if needed */
if ( stroker->center.x != stroker->subpath_start.x ||
stroker->center.y != stroker->subpath_start.y )
{
error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
if ( error )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -