📄 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 + -