1 /****************************************************************************
2 *
3 * ftstroke.c
4 *
5 * FreeType path stroker (body).
6 *
7 * Copyright (C) 2002-2019 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19 #include <ft2build.h>
20 #include FT_STROKER_H
21 #include FT_TRIGONOMETRY_H
22 #include FT_OUTLINE_H
23 #include FT_INTERNAL_MEMORY_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_OBJECTS_H
26
27
523
524 border->num_points += 3;
525 }
526
527 border->movable = FALSE;
528
529 return error;
530 }
531
532
533 #define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 )
534
535
536 static FT_Error
537 ft_stroke_border_arcto( FT_StrokeBorder border,
538 FT_Vector* center,
539 FT_Fixed radius,
540 FT_Angle angle_start,
541 FT_Angle angle_diff )
542 {
543 FT_Angle total, angle, step, rotate, next, theta;
544 FT_Vector a, b, a2, b2;
545 FT_Fixed length;
546 FT_Error error = FT_Err_Ok;
547
548
549 /* compute start point */
550 FT_Vector_From_Polar( &a, radius, angle_start );
551 a.x += center->x;
552 a.y += center->y;
553
554 total = angle_diff;
555 angle = angle_start;
556 rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
557
558 while ( total != 0 )
559 {
560 step = total;
561 if ( step > FT_ARC_CUBIC_ANGLE )
562 step = FT_ARC_CUBIC_ANGLE;
563
564 else if ( step < -FT_ARC_CUBIC_ANGLE )
565 step = -FT_ARC_CUBIC_ANGLE;
566
567 next = angle + step;
568 theta = step;
569 if ( theta < 0 )
570 theta = -theta;
571
572 theta >>= 1;
573
574 /* compute end point */
575 FT_Vector_From_Polar( &b, radius, next );
576 b.x += center->x;
577 b.y += center->y;
578
579 /* compute first and second control points */
580 length = FT_MulDiv( radius, FT_Sin( theta ) * 4,
581 ( 0x10000L + FT_Cos( theta ) ) * 3 );
582
583 FT_Vector_From_Polar( &a2, length, angle + rotate );
584 a2.x += a.x;
585 a2.y += a.y;
586
587 FT_Vector_From_Polar( &b2, length, next - rotate );
588 b2.x += b.x;
589 b2.y += b.y;
590
591 /* add cubic arc */
592 error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
593 if ( error )
594 break;
595
596 /* process the rest of the arc ?? */
597 a = b;
598 total -= step;
599 angle = next;
600 }
601
602 return error;
603 }
604
605
606 static FT_Error
607 ft_stroke_border_moveto( FT_StrokeBorder border,
608 FT_Vector* to )
609 {
610 /* close current open path if any ? */
611 if ( border->start >= 0 )
612 ft_stroke_border_close( border, FALSE );
613
614 border->start = (FT_Int)border->num_points;
615 border->movable = FALSE;
616
617 return ft_stroke_border_lineto( border, to, FALSE );
618 }
619
917 }
918
919
920 /* add a cap at the end of an opened path */
921 static FT_Error
922 ft_stroker_cap( FT_Stroker stroker,
923 FT_Angle angle,
924 FT_Int side )
925 {
926 FT_Error error = FT_Err_Ok;
927
928
929 if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
930 {
931 /* add a round cap */
932 stroker->angle_in = angle;
933 stroker->angle_out = angle + FT_ANGLE_PI;
934
935 error = ft_stroker_arcto( stroker, side );
936 }
937 else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
938 {
939 /* add a square cap */
940 FT_Vector delta, delta2;
941 FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
942 FT_Fixed radius = stroker->radius;
943 FT_StrokeBorder border = stroker->borders + side;
944
945
946 FT_Vector_From_Polar( &delta2, radius, angle + rotate );
947 FT_Vector_From_Polar( &delta, radius, angle );
948
949 delta.x += stroker->center.x + delta2.x;
950 delta.y += stroker->center.y + delta2.y;
951
952 error = ft_stroke_border_lineto( border, &delta, FALSE );
953 if ( error )
954 goto Exit;
955
956 FT_Vector_From_Polar( &delta2, radius, angle - rotate );
957 FT_Vector_From_Polar( &delta, radius, angle );
958
959 delta.x += delta2.x + stroker->center.x;
960 delta.y += delta2.y + stroker->center.y;
961
962 error = ft_stroke_border_lineto( border, &delta, FALSE );
963 }
964 else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT )
965 {
966 /* add a butt ending */
967 FT_Vector delta;
968 FT_Angle rotate = FT_SIDE_TO_ROTATE( side );
969 FT_Fixed radius = stroker->radius;
970 FT_StrokeBorder border = stroker->borders + side;
971
972
973 FT_Vector_From_Polar( &delta, radius, angle + rotate );
974
975 delta.x += stroker->center.x;
976 delta.y += stroker->center.y;
977
978 error = ft_stroke_border_lineto( border, &delta, FALSE );
979 if ( error )
980 goto Exit;
981
982 FT_Vector_From_Polar( &delta, radius, angle - rotate );
983
984 delta.x += stroker->center.x;
985 delta.y += stroker->center.y;
986
987 error = ft_stroke_border_lineto( border, &delta, FALSE );
988 }
989
990 Exit:
991 return error;
992 }
993
994
995 /* process an inside corner, i.e. compute intersection */
996 static FT_Error
997 ft_stroker_inside( FT_Stroker stroker,
998 FT_Int side,
999 FT_Fixed line_length )
1000 {
1001 FT_StrokeBorder border = stroker->borders + side;
1002 FT_Angle phi, theta, rotate;
1003 FT_Fixed length, thcos;
1004 FT_Vector delta;
1005 FT_Error error = FT_Err_Ok;
1006 FT_Bool intersect; /* use intersection of lines? */
1007
1008
1009 rotate = FT_SIDE_TO_ROTATE( side );
1010
1011 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2;
1012
1013 /* Only intersect borders if between two lineto's and both */
1014 /* lines are long enough (line_length is zero for curves). */
1015 /* Also avoid U-turns of nearly 180 degree. */
1016 if ( !border->movable || line_length == 0 ||
1017 theta > 0x59C000 || theta < -0x59C000 )
1018 intersect = FALSE;
1019 else
1020 {
1021 /* compute minimum required length of lines */
1022 FT_Fixed min_length = ft_pos_abs( FT_MulFix( stroker->radius,
1023 FT_Tan( theta ) ) );
1024
1025
1026 intersect = FT_BOOL( min_length &&
1027 stroker->line_length >= min_length &&
1028 line_length >= min_length );
1029 }
1030
1031 if ( !intersect )
1032 {
1033 FT_Vector_From_Polar( &delta, stroker->radius,
1034 stroker->angle_out + rotate );
1035 delta.x += stroker->center.x;
1036 delta.y += stroker->center.y;
1037
1038 border->movable = FALSE;
1039 }
1040 else
1041 {
1042 /* compute median angle */
1043 phi = stroker->angle_in + theta;
1044
1045 thcos = FT_Cos( theta );
1046
1047 length = FT_DivFix( stroker->radius, thcos );
1048
1049 FT_Vector_From_Polar( &delta, length, phi + rotate );
1050 delta.x += stroker->center.x;
1051 delta.y += stroker->center.y;
1052 }
1053
1054 error = ft_stroke_border_lineto( border, &delta, FALSE );
1055
1056 return error;
1057 }
1058
1059
1060 /* process an outside corner, i.e. compute bevel/miter/round */
1061 static FT_Error
1062 ft_stroker_outside( FT_Stroker stroker,
1063 FT_Int side,
1064 FT_Fixed line_length )
1065 {
1066 FT_StrokeBorder border = stroker->borders + side;
1067 FT_Error error;
1068 FT_Angle rotate;
1069
1070
1071 if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
1072 error = ft_stroker_arcto( stroker, side );
1073 else
1074 {
1075 /* this is a mitered (pointed) or beveled (truncated) corner */
1076 FT_Fixed sigma = 0, radius = stroker->radius;
1077 FT_Angle theta = 0, phi = 0;
1078 FT_Fixed thcos = 0;
1079 FT_Bool bevel, fixed_bevel;
1080
1081
1082 rotate = FT_SIDE_TO_ROTATE( side );
1083
1084 bevel =
1085 FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL );
1086
1087 fixed_bevel =
1088 FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE );
1089
1090 if ( !bevel )
1091 {
1092 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
1093
1094 if ( theta == FT_ANGLE_PI )
1095 {
1096 theta = rotate;
1097 phi = stroker->angle_in;
1098 }
1099 else
1100 {
1101 theta /= 2;
1102 phi = stroker->angle_in + theta + rotate;
1103 }
1104
1105 thcos = FT_Cos( theta );
1106 sigma = FT_MulFix( stroker->miter_limit, thcos );
1107
1108 /* is miter limit exceeded? */
1109 if ( sigma < 0x10000L )
1110 {
1111 /* don't create variable bevels for very small deviations; */
1112 /* FT_Sin(x) = 0 for x <= 57 */
1113 if ( fixed_bevel || ft_pos_abs( theta ) > 57 )
1114 bevel = TRUE;
1115 }
1116 }
1117
1118 if ( bevel ) /* this is a bevel (broken angle) */
1119 {
1120 if ( fixed_bevel )
1121 {
1122 /* the outer corners are simply joined together */
1123 FT_Vector delta;
1124
1125
1126 /* add bevel */
1127 FT_Vector_From_Polar( &delta,
1128 radius,
1129 stroker->angle_out + rotate );
1130 delta.x += stroker->center.x;
1131 delta.y += stroker->center.y;
1132
1133 border->movable = FALSE;
1134 error = ft_stroke_border_lineto( border, &delta, FALSE );
1135 }
1136 else /* variable bevel */
1137 {
1138 /* the miter is truncated */
1139 FT_Vector middle, delta;
1140 FT_Fixed length;
1141
1142
1143 /* compute middle point */
1144 FT_Vector_From_Polar( &middle,
1145 FT_MulFix( radius, stroker->miter_limit ),
1146 phi );
1147 middle.x += stroker->center.x;
1148 middle.y += stroker->center.y;
1149
1150 /* compute first angle point */
1151 length = FT_MulDiv( radius, 0x10000L - sigma,
1152 ft_pos_abs( FT_Sin( theta ) ) );
1153
1154 FT_Vector_From_Polar( &delta, length, phi + rotate );
1155 delta.x += middle.x;
1156 delta.y += middle.y;
1157
1158 error = ft_stroke_border_lineto( border, &delta, FALSE );
1159 if ( error )
1160 goto Exit;
1161
1162 /* compute second angle point */
1163 FT_Vector_From_Polar( &delta, length, phi - rotate );
1164 delta.x += middle.x;
1165 delta.y += middle.y;
1166
1167 error = ft_stroke_border_lineto( border, &delta, FALSE );
1168 if ( error )
1169 goto Exit;
1170
1171 /* finally, add an end point; only needed if not lineto */
1172 /* (line_length is zero for curves) */
1173 if ( line_length == 0 )
1174 {
1175 FT_Vector_From_Polar( &delta,
1176 radius,
1177 stroker->angle_out + rotate );
1178
1179 delta.x += stroker->center.x;
1180 delta.y += stroker->center.y;
1181
1182 error = ft_stroke_border_lineto( border, &delta, FALSE );
1183 }
1184 }
1185 }
1186 else /* this is a miter (intersection) */
1187 {
1188 FT_Fixed length;
1189 FT_Vector delta;
1190
1191
1192 length = FT_DivFix( stroker->radius, thcos );
1193
1194 FT_Vector_From_Polar( &delta, length, phi );
1195 delta.x += stroker->center.x;
1196 delta.y += stroker->center.y;
1197
1198 error = ft_stroke_border_lineto( border, &delta, FALSE );
1199 if ( error )
1200 goto Exit;
1201
1202 /* now add an end point; only needed if not lineto */
1203 /* (line_length is zero for curves) */
1204 if ( line_length == 0 )
1205 {
1206 FT_Vector_From_Polar( &delta,
1207 stroker->radius,
1208 stroker->angle_out + rotate );
1209 delta.x += stroker->center.x;
1210 delta.y += stroker->center.y;
1211
1212 error = ft_stroke_border_lineto( border, &delta, FALSE );
|
1 /****************************************************************************
2 *
3 * ftstroke.c
4 *
5 * FreeType path stroker (body).
6 *
7 * Copyright (C) 2002-2020 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19 #include <ft2build.h>
20 #include FT_STROKER_H
21 #include FT_TRIGONOMETRY_H
22 #include FT_OUTLINE_H
23 #include FT_INTERNAL_MEMORY_H
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_OBJECTS_H
26
27
523
524 border->num_points += 3;
525 }
526
527 border->movable = FALSE;
528
529 return error;
530 }
531
532
533 #define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 )
534
535
536 static FT_Error
537 ft_stroke_border_arcto( FT_StrokeBorder border,
538 FT_Vector* center,
539 FT_Fixed radius,
540 FT_Angle angle_start,
541 FT_Angle angle_diff )
542 {
543 FT_Fixed coef;
544 FT_Vector a0, a1, a2, a3;
545 FT_Int i, arcs = 1;
546 FT_Error error = FT_Err_Ok;
547
548
549 /* number of cubic arcs to draw */
550 while ( angle_diff > FT_ARC_CUBIC_ANGLE * arcs ||
551 -angle_diff > FT_ARC_CUBIC_ANGLE * arcs )
552 arcs++;
553
554 /* control tangents */
555 coef = FT_Tan( angle_diff / ( 4 * arcs ) );
556 coef += coef / 3;
557
558 /* compute start and first control point */
559 FT_Vector_From_Polar( &a0, radius, angle_start );
560 a1.x = FT_MulFix( -a0.y, coef );
561 a1.y = FT_MulFix( a0.x, coef );
562
563 a0.x += center->x;
564 a0.y += center->y;
565 a1.x += a0.x;
566 a1.y += a0.y;
567
568 for ( i = 1; i <= arcs; i++ )
569 {
570 /* compute end and second control point */
571 FT_Vector_From_Polar( &a3, radius,
572 angle_start + i * angle_diff / arcs );
573 a2.x = FT_MulFix( a3.y, coef );
574 a2.y = FT_MulFix( -a3.x, coef );
575
576 a3.x += center->x;
577 a3.y += center->y;
578 a2.x += a3.x;
579 a2.y += a3.y;
580
581 /* add cubic arc */
582 error = ft_stroke_border_cubicto( border, &a1, &a2, &a3 );
583 if ( error )
584 break;
585
586 /* a0 = a3; */
587 a1.x = a3.x - a2.x + a3.x;
588 a1.y = a3.y - a2.y + a3.y;
589 }
590
591 return error;
592 }
593
594
595 static FT_Error
596 ft_stroke_border_moveto( FT_StrokeBorder border,
597 FT_Vector* to )
598 {
599 /* close current open path if any ? */
600 if ( border->start >= 0 )
601 ft_stroke_border_close( border, FALSE );
602
603 border->start = (FT_Int)border->num_points;
604 border->movable = FALSE;
605
606 return ft_stroke_border_lineto( border, to, FALSE );
607 }
608
906 }
907
908
909 /* add a cap at the end of an opened path */
910 static FT_Error
911 ft_stroker_cap( FT_Stroker stroker,
912 FT_Angle angle,
913 FT_Int side )
914 {
915 FT_Error error = FT_Err_Ok;
916
917
918 if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
919 {
920 /* add a round cap */
921 stroker->angle_in = angle;
922 stroker->angle_out = angle + FT_ANGLE_PI;
923
924 error = ft_stroker_arcto( stroker, side );
925 }
926 else
927 {
928 /* add a square or butt cap */
929 FT_Vector middle, delta;
930 FT_Fixed radius = stroker->radius;
931 FT_StrokeBorder border = stroker->borders + side;
932
933
934 /* compute middle point and first angle point */
935 FT_Vector_From_Polar( &middle, radius, angle );
936 delta.x = side ? middle.y : -middle.y;
937 delta.y = side ? -middle.x : middle.x;
938
939 if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
940 {
941 middle.x += stroker->center.x;
942 middle.y += stroker->center.y;
943 }
944 else /* FT_STROKER_LINECAP_BUTT */
945 {
946 middle.x = stroker->center.x;
947 middle.y = stroker->center.y;
948 }
949
950 delta.x += middle.x;
951 delta.y += middle.y;
952
953 error = ft_stroke_border_lineto( border, &delta, FALSE );
954 if ( error )
955 goto Exit;
956
957 /* compute second angle point */
958 delta.x = middle.x - delta.x + middle.x;
959 delta.y = middle.y - delta.y + middle.y;
960
961 error = ft_stroke_border_lineto( border, &delta, FALSE );
962 }
963
964 Exit:
965 return error;
966 }
967
968
969 /* process an inside corner, i.e. compute intersection */
970 static FT_Error
971 ft_stroker_inside( FT_Stroker stroker,
972 FT_Int side,
973 FT_Fixed line_length )
974 {
975 FT_StrokeBorder border = stroker->borders + side;
976 FT_Angle phi, theta, rotate;
977 FT_Fixed length;
978 FT_Vector sigma, delta;
979 FT_Error error = FT_Err_Ok;
980 FT_Bool intersect; /* use intersection of lines? */
981
982
983 rotate = FT_SIDE_TO_ROTATE( side );
984
985 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2;
986
987 /* Only intersect borders if between two lineto's and both */
988 /* lines are long enough (line_length is zero for curves). */
989 /* Also avoid U-turns of nearly 180 degree. */
990 if ( !border->movable || line_length == 0 ||
991 theta > 0x59C000 || theta < -0x59C000 )
992 intersect = FALSE;
993 else
994 {
995 /* compute minimum required length of lines */
996 FT_Fixed min_length;
997
998
999 FT_Vector_Unit( &sigma, theta );
1000 min_length =
1001 ft_pos_abs( FT_MulDiv( stroker->radius, sigma.y, sigma.x ) );
1002
1003 intersect = FT_BOOL( min_length &&
1004 stroker->line_length >= min_length &&
1005 line_length >= min_length );
1006 }
1007
1008 if ( !intersect )
1009 {
1010 FT_Vector_From_Polar( &delta, stroker->radius,
1011 stroker->angle_out + rotate );
1012 delta.x += stroker->center.x;
1013 delta.y += stroker->center.y;
1014
1015 border->movable = FALSE;
1016 }
1017 else
1018 {
1019 /* compute median angle */
1020 phi = stroker->angle_in + theta + rotate;
1021
1022 length = FT_DivFix( stroker->radius, sigma.x );
1023
1024 FT_Vector_From_Polar( &delta, length, phi );
1025 delta.x += stroker->center.x;
1026 delta.y += stroker->center.y;
1027 }
1028
1029 error = ft_stroke_border_lineto( border, &delta, FALSE );
1030
1031 return error;
1032 }
1033
1034
1035 /* process an outside corner, i.e. compute bevel/miter/round */
1036 static FT_Error
1037 ft_stroker_outside( FT_Stroker stroker,
1038 FT_Int side,
1039 FT_Fixed line_length )
1040 {
1041 FT_StrokeBorder border = stroker->borders + side;
1042 FT_Error error;
1043 FT_Angle rotate;
1044
1045
1046 if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
1047 error = ft_stroker_arcto( stroker, side );
1048 else
1049 {
1050 /* this is a mitered (pointed) or beveled (truncated) corner */
1051 FT_Fixed radius = stroker->radius;
1052 FT_Vector sigma;
1053 FT_Angle theta = 0, phi = 0;
1054 FT_Bool bevel, fixed_bevel;
1055
1056
1057 rotate = FT_SIDE_TO_ROTATE( side );
1058
1059 bevel =
1060 FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_BEVEL );
1061
1062 fixed_bevel =
1063 FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE );
1064
1065 /* check miter limit first */
1066 if ( !bevel )
1067 {
1068 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2;
1069
1070 if ( theta == FT_ANGLE_PI2 )
1071 theta = -rotate;
1072
1073 phi = stroker->angle_in + theta + rotate;
1074
1075 FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta );
1076
1077 /* is miter limit exceeded? */
1078 if ( sigma.x < 0x10000L )
1079 {
1080 /* don't create variable bevels for very small deviations; */
1081 /* FT_Sin(x) = 0 for x <= 57 */
1082 if ( fixed_bevel || ft_pos_abs( theta ) > 57 )
1083 bevel = TRUE;
1084 }
1085 }
1086
1087 if ( bevel ) /* this is a bevel (broken angle) */
1088 {
1089 if ( fixed_bevel )
1090 {
1091 /* the outer corners are simply joined together */
1092 FT_Vector delta;
1093
1094
1095 /* add bevel */
1096 FT_Vector_From_Polar( &delta,
1097 radius,
1098 stroker->angle_out + rotate );
1099 delta.x += stroker->center.x;
1100 delta.y += stroker->center.y;
1101
1102 border->movable = FALSE;
1103 error = ft_stroke_border_lineto( border, &delta, FALSE );
1104 }
1105 else /* variable bevel or clipped miter */
1106 {
1107 /* the miter is truncated */
1108 FT_Vector middle, delta;
1109 FT_Fixed coef;
1110
1111
1112 /* compute middle point and first angle point */
1113 FT_Vector_From_Polar( &middle,
1114 FT_MulFix( radius, stroker->miter_limit ),
1115 phi );
1116
1117 coef = FT_DivFix( 0x10000L - sigma.x, sigma.y );
1118 delta.x = FT_MulFix( middle.y, coef );
1119 delta.y = FT_MulFix( -middle.x, coef );
1120
1121 middle.x += stroker->center.x;
1122 middle.y += stroker->center.y;
1123 delta.x += middle.x;
1124 delta.y += middle.y;
1125
1126 error = ft_stroke_border_lineto( border, &delta, FALSE );
1127 if ( error )
1128 goto Exit;
1129
1130 /* compute second angle point */
1131 delta.x = middle.x - delta.x + middle.x;
1132 delta.y = middle.y - delta.y + middle.y;
1133
1134 error = ft_stroke_border_lineto( border, &delta, FALSE );
1135 if ( error )
1136 goto Exit;
1137
1138 /* finally, add an end point; only needed if not lineto */
1139 /* (line_length is zero for curves) */
1140 if ( line_length == 0 )
1141 {
1142 FT_Vector_From_Polar( &delta,
1143 radius,
1144 stroker->angle_out + rotate );
1145
1146 delta.x += stroker->center.x;
1147 delta.y += stroker->center.y;
1148
1149 error = ft_stroke_border_lineto( border, &delta, FALSE );
1150 }
1151 }
1152 }
1153 else /* this is a miter (intersection) */
1154 {
1155 FT_Fixed length;
1156 FT_Vector delta;
1157
1158
1159 length = FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x );
1160
1161 FT_Vector_From_Polar( &delta, length, phi );
1162 delta.x += stroker->center.x;
1163 delta.y += stroker->center.y;
1164
1165 error = ft_stroke_border_lineto( border, &delta, FALSE );
1166 if ( error )
1167 goto Exit;
1168
1169 /* now add an end point; only needed if not lineto */
1170 /* (line_length is zero for curves) */
1171 if ( line_length == 0 )
1172 {
1173 FT_Vector_From_Polar( &delta,
1174 stroker->radius,
1175 stroker->angle_out + rotate );
1176 delta.x += stroker->center.x;
1177 delta.y += stroker->center.y;
1178
1179 error = ft_stroke_border_lineto( border, &delta, FALSE );
|