1*37da2899SCharles.Forsyth #include <ft2build.h> 2*37da2899SCharles.Forsyth #include FT_STROKER_H 3*37da2899SCharles.Forsyth #include FT_TRIGONOMETRY_H 4*37da2899SCharles.Forsyth #include FT_INTERNAL_MEMORY_H 5*37da2899SCharles.Forsyth #include FT_INTERNAL_DEBUG_H 6*37da2899SCharles.Forsyth 7*37da2899SCharles.Forsyth /***************************************************************************/ 8*37da2899SCharles.Forsyth /***************************************************************************/ 9*37da2899SCharles.Forsyth /***** *****/ 10*37da2899SCharles.Forsyth /***** BEZIER COMPUTATIONS *****/ 11*37da2899SCharles.Forsyth /***** *****/ 12*37da2899SCharles.Forsyth /***************************************************************************/ 13*37da2899SCharles.Forsyth /***************************************************************************/ 14*37da2899SCharles.Forsyth 15*37da2899SCharles.Forsyth #define FT_SMALL_CONIC_THRESHOLD (FT_ANGLE_PI/6) 16*37da2899SCharles.Forsyth #define FT_SMALL_CUBIC_THRESHOLD (FT_ANGLE_PI/6) 17*37da2899SCharles.Forsyth #define FT_EPSILON 2 18*37da2899SCharles.Forsyth 19*37da2899SCharles.Forsyth #define FT_IS_SMALL(x) ((x) > -FT_EPSILON && (x) < FT_EPSILON) 20*37da2899SCharles.Forsyth 21*37da2899SCharles.Forsyth static FT_Pos ft_pos_abs(FT_Pos x)22*37da2899SCharles.Forsyth ft_pos_abs( FT_Pos x ) 23*37da2899SCharles.Forsyth { 24*37da2899SCharles.Forsyth return x >= 0 ? x : -x ; 25*37da2899SCharles.Forsyth } 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsyth static void ft_conic_split(FT_Vector * base)28*37da2899SCharles.Forsyth ft_conic_split( FT_Vector* base ) 29*37da2899SCharles.Forsyth { 30*37da2899SCharles.Forsyth FT_Pos a, b; 31*37da2899SCharles.Forsyth 32*37da2899SCharles.Forsyth 33*37da2899SCharles.Forsyth base[4].x = base[2].x; 34*37da2899SCharles.Forsyth b = base[1].x; 35*37da2899SCharles.Forsyth a = base[3].x = ( base[2].x + b )/2; 36*37da2899SCharles.Forsyth b = base[1].x = ( base[0].x + b )/2; 37*37da2899SCharles.Forsyth base[2].x = ( a + b )/2; 38*37da2899SCharles.Forsyth 39*37da2899SCharles.Forsyth base[4].y = base[2].y; 40*37da2899SCharles.Forsyth b = base[1].y; 41*37da2899SCharles.Forsyth a = base[3].y = ( base[2].y + b )/2; 42*37da2899SCharles.Forsyth b = base[1].y = ( base[0].y + b )/2; 43*37da2899SCharles.Forsyth base[2].y = ( a + b )/2; 44*37da2899SCharles.Forsyth } 45*37da2899SCharles.Forsyth 46*37da2899SCharles.Forsyth 47*37da2899SCharles.Forsyth static FT_Bool ft_conic_is_small_enough(FT_Vector * base,FT_Angle * angle_in,FT_Angle * angle_out)48*37da2899SCharles.Forsyth ft_conic_is_small_enough( FT_Vector* base, 49*37da2899SCharles.Forsyth FT_Angle *angle_in, 50*37da2899SCharles.Forsyth FT_Angle *angle_out ) 51*37da2899SCharles.Forsyth { 52*37da2899SCharles.Forsyth FT_Vector d1, d2; 53*37da2899SCharles.Forsyth FT_Angle theta; 54*37da2899SCharles.Forsyth FT_Int close1, close2; 55*37da2899SCharles.Forsyth 56*37da2899SCharles.Forsyth d1.x = base[1].x - base[2].x; 57*37da2899SCharles.Forsyth d1.y = base[1].y - base[2].y; 58*37da2899SCharles.Forsyth d2.x = base[0].x - base[1].x; 59*37da2899SCharles.Forsyth d2.y = base[0].y - base[1].y; 60*37da2899SCharles.Forsyth 61*37da2899SCharles.Forsyth close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y); 62*37da2899SCharles.Forsyth close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y); 63*37da2899SCharles.Forsyth 64*37da2899SCharles.Forsyth if (close1) 65*37da2899SCharles.Forsyth { 66*37da2899SCharles.Forsyth if (close2) 67*37da2899SCharles.Forsyth *angle_in = *angle_out = 0; 68*37da2899SCharles.Forsyth else 69*37da2899SCharles.Forsyth *angle_in = *angle_out = FT_Atan2( d2.x, d2.y ); 70*37da2899SCharles.Forsyth } 71*37da2899SCharles.Forsyth else if (close2) 72*37da2899SCharles.Forsyth { 73*37da2899SCharles.Forsyth *angle_in = *angle_out = FT_Atan2( d1.x, d1.y ); 74*37da2899SCharles.Forsyth } 75*37da2899SCharles.Forsyth else 76*37da2899SCharles.Forsyth { 77*37da2899SCharles.Forsyth *angle_in = FT_Atan2( d1.x, d1.y ); 78*37da2899SCharles.Forsyth *angle_out = FT_Atan2( d2.x, d2.y ); 79*37da2899SCharles.Forsyth } 80*37da2899SCharles.Forsyth 81*37da2899SCharles.Forsyth theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); 82*37da2899SCharles.Forsyth 83*37da2899SCharles.Forsyth return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); 84*37da2899SCharles.Forsyth } 85*37da2899SCharles.Forsyth 86*37da2899SCharles.Forsyth 87*37da2899SCharles.Forsyth static void ft_cubic_split(FT_Vector * base)88*37da2899SCharles.Forsyth ft_cubic_split( FT_Vector* base ) 89*37da2899SCharles.Forsyth { 90*37da2899SCharles.Forsyth FT_Pos a, b, c, d; 91*37da2899SCharles.Forsyth 92*37da2899SCharles.Forsyth 93*37da2899SCharles.Forsyth base[6].x = base[3].x; 94*37da2899SCharles.Forsyth c = base[1].x; 95*37da2899SCharles.Forsyth d = base[2].x; 96*37da2899SCharles.Forsyth base[1].x = a = ( base[0].x + c )/2; 97*37da2899SCharles.Forsyth base[5].x = b = ( base[3].x + d )/2; 98*37da2899SCharles.Forsyth c = ( c + d )/2; 99*37da2899SCharles.Forsyth base[2].x = a = ( a + c )/2; 100*37da2899SCharles.Forsyth base[4].x = b = ( b + c )/2; 101*37da2899SCharles.Forsyth base[3].x = ( a + b )/2; 102*37da2899SCharles.Forsyth 103*37da2899SCharles.Forsyth base[6].y = base[3].y; 104*37da2899SCharles.Forsyth c = base[1].y; 105*37da2899SCharles.Forsyth d = base[2].y; 106*37da2899SCharles.Forsyth base[1].y = a = ( base[0].y + c )/2; 107*37da2899SCharles.Forsyth base[5].y = b = ( base[3].y + d )/2; 108*37da2899SCharles.Forsyth c = ( c + d )/2; 109*37da2899SCharles.Forsyth base[2].y = a = ( a + c )/2; 110*37da2899SCharles.Forsyth base[4].y = b = ( b + c )/2; 111*37da2899SCharles.Forsyth base[3].y = ( a + b )/2; 112*37da2899SCharles.Forsyth } 113*37da2899SCharles.Forsyth 114*37da2899SCharles.Forsyth 115*37da2899SCharles.Forsyth static FT_Bool ft_cubic_is_small_enough(FT_Vector * base,FT_Angle * angle_in,FT_Angle * angle_mid,FT_Angle * angle_out)116*37da2899SCharles.Forsyth ft_cubic_is_small_enough( FT_Vector* base, 117*37da2899SCharles.Forsyth FT_Angle *angle_in, 118*37da2899SCharles.Forsyth FT_Angle *angle_mid, 119*37da2899SCharles.Forsyth FT_Angle *angle_out ) 120*37da2899SCharles.Forsyth { 121*37da2899SCharles.Forsyth FT_Vector d1, d2, d3; 122*37da2899SCharles.Forsyth FT_Angle theta1, theta2; 123*37da2899SCharles.Forsyth FT_Int close1, close2, close3; 124*37da2899SCharles.Forsyth 125*37da2899SCharles.Forsyth d1.x = base[2].x - base[3].x; 126*37da2899SCharles.Forsyth d1.y = base[2].y - base[3].y; 127*37da2899SCharles.Forsyth d2.x = base[1].x - base[2].x; 128*37da2899SCharles.Forsyth d2.y = base[1].y - base[2].y; 129*37da2899SCharles.Forsyth d3.x = base[0].x - base[1].x; 130*37da2899SCharles.Forsyth d3.y = base[0].y - base[1].y; 131*37da2899SCharles.Forsyth 132*37da2899SCharles.Forsyth close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y); 133*37da2899SCharles.Forsyth close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y); 134*37da2899SCharles.Forsyth close3 = FT_IS_SMALL(d3.x) && FT_IS_SMALL(d3.y); 135*37da2899SCharles.Forsyth 136*37da2899SCharles.Forsyth if (close1 || close3) 137*37da2899SCharles.Forsyth { 138*37da2899SCharles.Forsyth if (close2) 139*37da2899SCharles.Forsyth { 140*37da2899SCharles.Forsyth /* basically a point */ 141*37da2899SCharles.Forsyth *angle_in = *angle_out = *angle_mid = 0; 142*37da2899SCharles.Forsyth } 143*37da2899SCharles.Forsyth else if (close1) 144*37da2899SCharles.Forsyth { 145*37da2899SCharles.Forsyth *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y ); 146*37da2899SCharles.Forsyth *angle_out = FT_Atan2( d3.x, d3.y ); 147*37da2899SCharles.Forsyth } 148*37da2899SCharles.Forsyth else /* close2 */ 149*37da2899SCharles.Forsyth { 150*37da2899SCharles.Forsyth *angle_in = FT_Atan2( d1.x, d1.y ); 151*37da2899SCharles.Forsyth *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y ); 152*37da2899SCharles.Forsyth } 153*37da2899SCharles.Forsyth } 154*37da2899SCharles.Forsyth else if (close2) 155*37da2899SCharles.Forsyth { 156*37da2899SCharles.Forsyth *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y ); 157*37da2899SCharles.Forsyth *angle_out = FT_Atan2( d3.x, d3.y ); 158*37da2899SCharles.Forsyth } 159*37da2899SCharles.Forsyth else 160*37da2899SCharles.Forsyth { 161*37da2899SCharles.Forsyth *angle_in = FT_Atan2( d1.x, d1.y ); 162*37da2899SCharles.Forsyth *angle_mid = FT_Atan2( d2.x, d2.y ); 163*37da2899SCharles.Forsyth *angle_out = FT_Atan2( d3.x, d3.y ); 164*37da2899SCharles.Forsyth } 165*37da2899SCharles.Forsyth theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); 166*37da2899SCharles.Forsyth theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); 167*37da2899SCharles.Forsyth 168*37da2899SCharles.Forsyth return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && 169*37da2899SCharles.Forsyth theta2 < FT_SMALL_CUBIC_THRESHOLD ); 170*37da2899SCharles.Forsyth } 171*37da2899SCharles.Forsyth 172*37da2899SCharles.Forsyth 173*37da2899SCharles.Forsyth 174*37da2899SCharles.Forsyth /***************************************************************************/ 175*37da2899SCharles.Forsyth /***************************************************************************/ 176*37da2899SCharles.Forsyth /***** *****/ 177*37da2899SCharles.Forsyth /***** STROKE BORDERS *****/ 178*37da2899SCharles.Forsyth /***** *****/ 179*37da2899SCharles.Forsyth /***************************************************************************/ 180*37da2899SCharles.Forsyth /***************************************************************************/ 181*37da2899SCharles.Forsyth 182*37da2899SCharles.Forsyth typedef enum 183*37da2899SCharles.Forsyth { 184*37da2899SCharles.Forsyth FT_STROKE_TAG_ON = 1, /* on-curve point */ 185*37da2899SCharles.Forsyth FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ 186*37da2899SCharles.Forsyth FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ 187*37da2899SCharles.Forsyth FT_STROKE_TAG_END = 8 /* sub-path end */ 188*37da2899SCharles.Forsyth 189*37da2899SCharles.Forsyth } FT_StrokeTags; 190*37da2899SCharles.Forsyth 191*37da2899SCharles.Forsyth 192*37da2899SCharles.Forsyth typedef struct FT_StrokeBorderRec_ 193*37da2899SCharles.Forsyth { 194*37da2899SCharles.Forsyth FT_UInt num_points; 195*37da2899SCharles.Forsyth FT_UInt max_points; 196*37da2899SCharles.Forsyth FT_Vector* points; 197*37da2899SCharles.Forsyth FT_Byte* tags; 198*37da2899SCharles.Forsyth FT_Bool movable; 199*37da2899SCharles.Forsyth FT_Int start; /* index of current sub-path start point */ 200*37da2899SCharles.Forsyth FT_Memory memory; 201*37da2899SCharles.Forsyth 202*37da2899SCharles.Forsyth } FT_StrokeBorderRec, *FT_StrokeBorder; 203*37da2899SCharles.Forsyth 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_grow(FT_StrokeBorder border,FT_UInt new_points)206*37da2899SCharles.Forsyth ft_stroke_border_grow( FT_StrokeBorder border, 207*37da2899SCharles.Forsyth FT_UInt new_points ) 208*37da2899SCharles.Forsyth { 209*37da2899SCharles.Forsyth FT_UInt old_max = border->max_points; 210*37da2899SCharles.Forsyth FT_UInt new_max = border->num_points + new_points; 211*37da2899SCharles.Forsyth FT_Error error = 0; 212*37da2899SCharles.Forsyth 213*37da2899SCharles.Forsyth if ( new_max > old_max ) 214*37da2899SCharles.Forsyth { 215*37da2899SCharles.Forsyth FT_UInt cur_max = old_max; 216*37da2899SCharles.Forsyth FT_Memory memory = border->memory; 217*37da2899SCharles.Forsyth 218*37da2899SCharles.Forsyth while ( cur_max < new_max ) 219*37da2899SCharles.Forsyth cur_max += (cur_max >> 1) + 16; 220*37da2899SCharles.Forsyth 221*37da2899SCharles.Forsyth if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || 222*37da2899SCharles.Forsyth FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) 223*37da2899SCharles.Forsyth goto Exit; 224*37da2899SCharles.Forsyth 225*37da2899SCharles.Forsyth border->max_points = cur_max; 226*37da2899SCharles.Forsyth } 227*37da2899SCharles.Forsyth Exit: 228*37da2899SCharles.Forsyth return error; 229*37da2899SCharles.Forsyth } 230*37da2899SCharles.Forsyth 231*37da2899SCharles.Forsyth static void ft_stroke_border_close(FT_StrokeBorder border)232*37da2899SCharles.Forsyth ft_stroke_border_close( FT_StrokeBorder border ) 233*37da2899SCharles.Forsyth { 234*37da2899SCharles.Forsyth FT_ASSERT( border->start >= 0 ); 235*37da2899SCharles.Forsyth 236*37da2899SCharles.Forsyth border->tags[ border->start ] |= FT_STROKE_TAG_BEGIN; 237*37da2899SCharles.Forsyth border->tags[ border->num_points-1 ] |= FT_STROKE_TAG_END; 238*37da2899SCharles.Forsyth 239*37da2899SCharles.Forsyth border->start = -1; 240*37da2899SCharles.Forsyth border->movable = 0; 241*37da2899SCharles.Forsyth } 242*37da2899SCharles.Forsyth 243*37da2899SCharles.Forsyth 244*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_lineto(FT_StrokeBorder border,FT_Vector * to,FT_Bool movable)245*37da2899SCharles.Forsyth ft_stroke_border_lineto( FT_StrokeBorder border, 246*37da2899SCharles.Forsyth FT_Vector* to, 247*37da2899SCharles.Forsyth FT_Bool movable ) 248*37da2899SCharles.Forsyth { 249*37da2899SCharles.Forsyth FT_Error error = 0; 250*37da2899SCharles.Forsyth 251*37da2899SCharles.Forsyth FT_ASSERT( border->start >= 0 ); 252*37da2899SCharles.Forsyth 253*37da2899SCharles.Forsyth if ( border->movable ) 254*37da2899SCharles.Forsyth { 255*37da2899SCharles.Forsyth /* move last point */ 256*37da2899SCharles.Forsyth border->points[ border->num_points-1 ] = *to; 257*37da2899SCharles.Forsyth } 258*37da2899SCharles.Forsyth else 259*37da2899SCharles.Forsyth { 260*37da2899SCharles.Forsyth /* add one point */ 261*37da2899SCharles.Forsyth error = ft_stroke_border_grow( border, 1 ); 262*37da2899SCharles.Forsyth if (!error) 263*37da2899SCharles.Forsyth { 264*37da2899SCharles.Forsyth FT_Vector* vec = border->points + border->num_points; 265*37da2899SCharles.Forsyth FT_Byte* tag = border->tags + border->num_points; 266*37da2899SCharles.Forsyth 267*37da2899SCharles.Forsyth vec[0] = *to; 268*37da2899SCharles.Forsyth tag[0] = FT_STROKE_TAG_ON; 269*37da2899SCharles.Forsyth 270*37da2899SCharles.Forsyth border->num_points += 1; 271*37da2899SCharles.Forsyth } 272*37da2899SCharles.Forsyth } 273*37da2899SCharles.Forsyth border->movable = movable; 274*37da2899SCharles.Forsyth return error; 275*37da2899SCharles.Forsyth } 276*37da2899SCharles.Forsyth 277*37da2899SCharles.Forsyth 278*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_conicto(FT_StrokeBorder border,FT_Vector * control,FT_Vector * to)279*37da2899SCharles.Forsyth ft_stroke_border_conicto( FT_StrokeBorder border, 280*37da2899SCharles.Forsyth FT_Vector* control, 281*37da2899SCharles.Forsyth FT_Vector* to ) 282*37da2899SCharles.Forsyth { 283*37da2899SCharles.Forsyth FT_Error error; 284*37da2899SCharles.Forsyth 285*37da2899SCharles.Forsyth FT_ASSERT( border->start >= 0 ); 286*37da2899SCharles.Forsyth 287*37da2899SCharles.Forsyth error = ft_stroke_border_grow( border, 2 ); 288*37da2899SCharles.Forsyth if (!error) 289*37da2899SCharles.Forsyth { 290*37da2899SCharles.Forsyth FT_Vector* vec = border->points + border->num_points; 291*37da2899SCharles.Forsyth FT_Byte* tag = border->tags + border->num_points; 292*37da2899SCharles.Forsyth 293*37da2899SCharles.Forsyth vec[0] = *control; 294*37da2899SCharles.Forsyth vec[1] = *to; 295*37da2899SCharles.Forsyth 296*37da2899SCharles.Forsyth tag[0] = 0; 297*37da2899SCharles.Forsyth tag[1] = FT_STROKE_TAG_ON; 298*37da2899SCharles.Forsyth 299*37da2899SCharles.Forsyth border->num_points += 2; 300*37da2899SCharles.Forsyth } 301*37da2899SCharles.Forsyth border->movable = 0; 302*37da2899SCharles.Forsyth return error; 303*37da2899SCharles.Forsyth } 304*37da2899SCharles.Forsyth 305*37da2899SCharles.Forsyth 306*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_cubicto(FT_StrokeBorder border,FT_Vector * control1,FT_Vector * control2,FT_Vector * to)307*37da2899SCharles.Forsyth ft_stroke_border_cubicto( FT_StrokeBorder border, 308*37da2899SCharles.Forsyth FT_Vector* control1, 309*37da2899SCharles.Forsyth FT_Vector* control2, 310*37da2899SCharles.Forsyth FT_Vector* to ) 311*37da2899SCharles.Forsyth { 312*37da2899SCharles.Forsyth FT_Error error; 313*37da2899SCharles.Forsyth 314*37da2899SCharles.Forsyth FT_ASSERT( border->start >= 0 ); 315*37da2899SCharles.Forsyth 316*37da2899SCharles.Forsyth error = ft_stroke_border_grow( border, 3 ); 317*37da2899SCharles.Forsyth if (!error) 318*37da2899SCharles.Forsyth { 319*37da2899SCharles.Forsyth FT_Vector* vec = border->points + border->num_points; 320*37da2899SCharles.Forsyth FT_Byte* tag = border->tags + border->num_points; 321*37da2899SCharles.Forsyth 322*37da2899SCharles.Forsyth vec[0] = *control1; 323*37da2899SCharles.Forsyth vec[1] = *control2; 324*37da2899SCharles.Forsyth vec[2] = *to; 325*37da2899SCharles.Forsyth 326*37da2899SCharles.Forsyth tag[0] = FT_STROKE_TAG_CUBIC; 327*37da2899SCharles.Forsyth tag[1] = FT_STROKE_TAG_CUBIC; 328*37da2899SCharles.Forsyth tag[2] = FT_STROKE_TAG_ON; 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsyth border->num_points += 3; 331*37da2899SCharles.Forsyth } 332*37da2899SCharles.Forsyth border->movable = 0; 333*37da2899SCharles.Forsyth return error; 334*37da2899SCharles.Forsyth } 335*37da2899SCharles.Forsyth 336*37da2899SCharles.Forsyth 337*37da2899SCharles.Forsyth #define FT_ARC_CUBIC_ANGLE (FT_ANGLE_PI/2) 338*37da2899SCharles.Forsyth 339*37da2899SCharles.Forsyth 340*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_arcto(FT_StrokeBorder border,FT_Vector * center,FT_Fixed radius,FT_Angle angle_start,FT_Angle angle_diff)341*37da2899SCharles.Forsyth ft_stroke_border_arcto( FT_StrokeBorder border, 342*37da2899SCharles.Forsyth FT_Vector* center, 343*37da2899SCharles.Forsyth FT_Fixed radius, 344*37da2899SCharles.Forsyth FT_Angle angle_start, 345*37da2899SCharles.Forsyth FT_Angle angle_diff ) 346*37da2899SCharles.Forsyth { 347*37da2899SCharles.Forsyth FT_Angle total, angle, step, rotate, next, theta; 348*37da2899SCharles.Forsyth FT_Vector a, b, a2, b2; 349*37da2899SCharles.Forsyth FT_Fixed length; 350*37da2899SCharles.Forsyth FT_Error error = 0; 351*37da2899SCharles.Forsyth 352*37da2899SCharles.Forsyth /* compute start point */ 353*37da2899SCharles.Forsyth FT_Vector_From_Polar( &a, radius, angle_start ); 354*37da2899SCharles.Forsyth a.x += center->x; 355*37da2899SCharles.Forsyth a.y += center->y; 356*37da2899SCharles.Forsyth 357*37da2899SCharles.Forsyth total = angle_diff; 358*37da2899SCharles.Forsyth angle = angle_start; 359*37da2899SCharles.Forsyth rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2; 360*37da2899SCharles.Forsyth 361*37da2899SCharles.Forsyth while (total != 0) 362*37da2899SCharles.Forsyth { 363*37da2899SCharles.Forsyth step = total; 364*37da2899SCharles.Forsyth if ( step > FT_ARC_CUBIC_ANGLE ) 365*37da2899SCharles.Forsyth step = FT_ARC_CUBIC_ANGLE; 366*37da2899SCharles.Forsyth 367*37da2899SCharles.Forsyth else if ( step < -FT_ARC_CUBIC_ANGLE ) 368*37da2899SCharles.Forsyth step = -FT_ARC_CUBIC_ANGLE; 369*37da2899SCharles.Forsyth 370*37da2899SCharles.Forsyth next = angle + step; 371*37da2899SCharles.Forsyth theta = step; 372*37da2899SCharles.Forsyth if ( theta < 0 ) 373*37da2899SCharles.Forsyth theta = -theta; 374*37da2899SCharles.Forsyth 375*37da2899SCharles.Forsyth theta >>= 1; 376*37da2899SCharles.Forsyth 377*37da2899SCharles.Forsyth /* compute end point */ 378*37da2899SCharles.Forsyth FT_Vector_From_Polar( &b, radius, next ); 379*37da2899SCharles.Forsyth b.x += center->x; 380*37da2899SCharles.Forsyth b.y += center->y; 381*37da2899SCharles.Forsyth 382*37da2899SCharles.Forsyth /* compute first and second control points */ 383*37da2899SCharles.Forsyth length = FT_MulDiv( radius, FT_Sin(theta)*4, 384*37da2899SCharles.Forsyth (0x10000L + FT_Cos(theta))*3 ); 385*37da2899SCharles.Forsyth 386*37da2899SCharles.Forsyth FT_Vector_From_Polar( &a2, length, angle + rotate ); 387*37da2899SCharles.Forsyth a2.x += a.x; 388*37da2899SCharles.Forsyth a2.y += a.y; 389*37da2899SCharles.Forsyth 390*37da2899SCharles.Forsyth FT_Vector_From_Polar( &b2, length, next - rotate ); 391*37da2899SCharles.Forsyth b2.x += b.x; 392*37da2899SCharles.Forsyth b2.y += b.y; 393*37da2899SCharles.Forsyth 394*37da2899SCharles.Forsyth /* add cubic arc */ 395*37da2899SCharles.Forsyth error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); 396*37da2899SCharles.Forsyth if (error) break; 397*37da2899SCharles.Forsyth 398*37da2899SCharles.Forsyth /* process the rest of the arc ?? */ 399*37da2899SCharles.Forsyth a = b; 400*37da2899SCharles.Forsyth total -= step; 401*37da2899SCharles.Forsyth angle = next; 402*37da2899SCharles.Forsyth } 403*37da2899SCharles.Forsyth return error; 404*37da2899SCharles.Forsyth } 405*37da2899SCharles.Forsyth 406*37da2899SCharles.Forsyth 407*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_moveto(FT_StrokeBorder border,FT_Vector * to)408*37da2899SCharles.Forsyth ft_stroke_border_moveto( FT_StrokeBorder border, 409*37da2899SCharles.Forsyth FT_Vector* to ) 410*37da2899SCharles.Forsyth { 411*37da2899SCharles.Forsyth /* close current open path if any ? */ 412*37da2899SCharles.Forsyth if ( border->start >= 0 ) 413*37da2899SCharles.Forsyth ft_stroke_border_close( border ); 414*37da2899SCharles.Forsyth 415*37da2899SCharles.Forsyth border->start = border->num_points; 416*37da2899SCharles.Forsyth border->movable = 0; 417*37da2899SCharles.Forsyth 418*37da2899SCharles.Forsyth return ft_stroke_border_lineto( border, to, 0 ); 419*37da2899SCharles.Forsyth } 420*37da2899SCharles.Forsyth 421*37da2899SCharles.Forsyth 422*37da2899SCharles.Forsyth static void ft_stroke_border_init(FT_StrokeBorder border,FT_Memory memory)423*37da2899SCharles.Forsyth ft_stroke_border_init( FT_StrokeBorder border, 424*37da2899SCharles.Forsyth FT_Memory memory ) 425*37da2899SCharles.Forsyth { 426*37da2899SCharles.Forsyth border->memory = memory; 427*37da2899SCharles.Forsyth border->points = NULL; 428*37da2899SCharles.Forsyth border->tags = NULL; 429*37da2899SCharles.Forsyth 430*37da2899SCharles.Forsyth border->num_points = 0; 431*37da2899SCharles.Forsyth border->max_points = 0; 432*37da2899SCharles.Forsyth border->start = -1; 433*37da2899SCharles.Forsyth } 434*37da2899SCharles.Forsyth 435*37da2899SCharles.Forsyth 436*37da2899SCharles.Forsyth static void ft_stroke_border_reset(FT_StrokeBorder border)437*37da2899SCharles.Forsyth ft_stroke_border_reset( FT_StrokeBorder border ) 438*37da2899SCharles.Forsyth { 439*37da2899SCharles.Forsyth border->num_points = 0; 440*37da2899SCharles.Forsyth border->start = -1; 441*37da2899SCharles.Forsyth } 442*37da2899SCharles.Forsyth 443*37da2899SCharles.Forsyth 444*37da2899SCharles.Forsyth static void ft_stroke_border_done(FT_StrokeBorder border)445*37da2899SCharles.Forsyth ft_stroke_border_done( FT_StrokeBorder border ) 446*37da2899SCharles.Forsyth { 447*37da2899SCharles.Forsyth FT_Memory memory = border->memory; 448*37da2899SCharles.Forsyth 449*37da2899SCharles.Forsyth FT_FREE( border->points ); 450*37da2899SCharles.Forsyth FT_FREE( border->tags ); 451*37da2899SCharles.Forsyth 452*37da2899SCharles.Forsyth border->num_points = 0; 453*37da2899SCharles.Forsyth border->max_points = 0; 454*37da2899SCharles.Forsyth border->start = -1; 455*37da2899SCharles.Forsyth } 456*37da2899SCharles.Forsyth 457*37da2899SCharles.Forsyth 458*37da2899SCharles.Forsyth static FT_Error ft_stroke_border_get_counts(FT_StrokeBorder border,FT_UInt * anum_points,FT_UInt * anum_contours)459*37da2899SCharles.Forsyth ft_stroke_border_get_counts( FT_StrokeBorder border, 460*37da2899SCharles.Forsyth FT_UInt *anum_points, 461*37da2899SCharles.Forsyth FT_UInt *anum_contours ) 462*37da2899SCharles.Forsyth { 463*37da2899SCharles.Forsyth FT_Error error = 0; 464*37da2899SCharles.Forsyth FT_UInt num_points = 0; 465*37da2899SCharles.Forsyth FT_UInt num_contours = 0; 466*37da2899SCharles.Forsyth 467*37da2899SCharles.Forsyth FT_UInt count = border->num_points; 468*37da2899SCharles.Forsyth FT_Vector* point = border->points; 469*37da2899SCharles.Forsyth FT_Byte* tags = border->tags; 470*37da2899SCharles.Forsyth FT_Int in_contour = 0; 471*37da2899SCharles.Forsyth 472*37da2899SCharles.Forsyth for ( ; count > 0; count--, point++, tags++ ) 473*37da2899SCharles.Forsyth { 474*37da2899SCharles.Forsyth if ( tags[0] & FT_STROKE_TAG_BEGIN ) 475*37da2899SCharles.Forsyth { 476*37da2899SCharles.Forsyth if ( in_contour != 0 ) 477*37da2899SCharles.Forsyth goto Fail; 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsyth in_contour = 1; 480*37da2899SCharles.Forsyth } 481*37da2899SCharles.Forsyth else if ( in_contour == 0 ) 482*37da2899SCharles.Forsyth goto Fail; 483*37da2899SCharles.Forsyth 484*37da2899SCharles.Forsyth if ( tags[0] & FT_STROKE_TAG_END ) 485*37da2899SCharles.Forsyth { 486*37da2899SCharles.Forsyth if ( in_contour == 0 ) 487*37da2899SCharles.Forsyth goto Fail; 488*37da2899SCharles.Forsyth 489*37da2899SCharles.Forsyth in_contour = 0; 490*37da2899SCharles.Forsyth num_contours++; 491*37da2899SCharles.Forsyth } 492*37da2899SCharles.Forsyth } 493*37da2899SCharles.Forsyth if ( in_contour != 0 ) 494*37da2899SCharles.Forsyth goto Fail; 495*37da2899SCharles.Forsyth 496*37da2899SCharles.Forsyth Exit: 497*37da2899SCharles.Forsyth *anum_points = num_points; 498*37da2899SCharles.Forsyth *anum_contours = num_contours; 499*37da2899SCharles.Forsyth return error; 500*37da2899SCharles.Forsyth 501*37da2899SCharles.Forsyth Fail: 502*37da2899SCharles.Forsyth num_points = 0; 503*37da2899SCharles.Forsyth num_contours = 0; 504*37da2899SCharles.Forsyth goto Exit; 505*37da2899SCharles.Forsyth } 506*37da2899SCharles.Forsyth 507*37da2899SCharles.Forsyth 508*37da2899SCharles.Forsyth static void ft_stroke_border_export(FT_StrokeBorder border,FT_Outline * outline)509*37da2899SCharles.Forsyth ft_stroke_border_export( FT_StrokeBorder border, 510*37da2899SCharles.Forsyth FT_Outline* outline ) 511*37da2899SCharles.Forsyth { 512*37da2899SCharles.Forsyth /* copy point locations */ 513*37da2899SCharles.Forsyth FT_MEM_COPY( outline->points + outline->n_points, 514*37da2899SCharles.Forsyth border->points, 515*37da2899SCharles.Forsyth border->num_points * sizeof(FT_Vector) ); 516*37da2899SCharles.Forsyth 517*37da2899SCharles.Forsyth /* copy tags */ 518*37da2899SCharles.Forsyth { 519*37da2899SCharles.Forsyth FT_UInt count = border->num_points; 520*37da2899SCharles.Forsyth FT_Byte* read = border->tags; 521*37da2899SCharles.Forsyth FT_Byte* write = (FT_Byte*) outline->tags + outline->n_points; 522*37da2899SCharles.Forsyth 523*37da2899SCharles.Forsyth for ( ; count > 0; count--, read++, write++ ) 524*37da2899SCharles.Forsyth { 525*37da2899SCharles.Forsyth if ( *read & FT_STROKE_TAG_ON ) 526*37da2899SCharles.Forsyth *write = FT_CURVE_TAG_ON; 527*37da2899SCharles.Forsyth else if ( *read & FT_STROKE_TAG_CUBIC ) 528*37da2899SCharles.Forsyth *write = FT_CURVE_TAG_CUBIC; 529*37da2899SCharles.Forsyth else 530*37da2899SCharles.Forsyth *write = FT_CURVE_TAG_CONIC; 531*37da2899SCharles.Forsyth } 532*37da2899SCharles.Forsyth } 533*37da2899SCharles.Forsyth 534*37da2899SCharles.Forsyth /* copy contours */ 535*37da2899SCharles.Forsyth { 536*37da2899SCharles.Forsyth FT_UInt count = border->num_points; 537*37da2899SCharles.Forsyth FT_Byte* tags = border->tags; 538*37da2899SCharles.Forsyth FT_Short* write = outline->contours + outline->n_contours; 539*37da2899SCharles.Forsyth FT_Short index = (FT_Short) outline->n_points; 540*37da2899SCharles.Forsyth 541*37da2899SCharles.Forsyth for ( ; count > 0; count--, tags++, write++, index++ ) 542*37da2899SCharles.Forsyth { 543*37da2899SCharles.Forsyth if ( *tags & FT_STROKE_TAG_END ) 544*37da2899SCharles.Forsyth { 545*37da2899SCharles.Forsyth *write++ = index; 546*37da2899SCharles.Forsyth outline->n_contours++; 547*37da2899SCharles.Forsyth } 548*37da2899SCharles.Forsyth } 549*37da2899SCharles.Forsyth } 550*37da2899SCharles.Forsyth 551*37da2899SCharles.Forsyth outline->n_points = (short)( outline->n_points + border->num_points ); 552*37da2899SCharles.Forsyth 553*37da2899SCharles.Forsyth FT_ASSERT( FT_Outline_Check( outline ) == 0 ); 554*37da2899SCharles.Forsyth } 555*37da2899SCharles.Forsyth 556*37da2899SCharles.Forsyth 557*37da2899SCharles.Forsyth /***************************************************************************/ 558*37da2899SCharles.Forsyth /***************************************************************************/ 559*37da2899SCharles.Forsyth /***** *****/ 560*37da2899SCharles.Forsyth /***** STROKER *****/ 561*37da2899SCharles.Forsyth /***** *****/ 562*37da2899SCharles.Forsyth /***************************************************************************/ 563*37da2899SCharles.Forsyth /***************************************************************************/ 564*37da2899SCharles.Forsyth 565*37da2899SCharles.Forsyth #define FT_SIDE_TO_ROTATE(s) (FT_ANGLE_PI2 - (s)*FT_ANGLE_PI) 566*37da2899SCharles.Forsyth 567*37da2899SCharles.Forsyth typedef struct FT_StrokerRec_ 568*37da2899SCharles.Forsyth { 569*37da2899SCharles.Forsyth FT_Angle angle_in; 570*37da2899SCharles.Forsyth FT_Angle angle_out; 571*37da2899SCharles.Forsyth FT_Vector center; 572*37da2899SCharles.Forsyth FT_Bool first_point; 573*37da2899SCharles.Forsyth FT_Bool subpath_open; 574*37da2899SCharles.Forsyth FT_Angle subpath_angle; 575*37da2899SCharles.Forsyth FT_Vector subpath_start; 576*37da2899SCharles.Forsyth 577*37da2899SCharles.Forsyth FT_Stroker_LineCap line_cap; 578*37da2899SCharles.Forsyth FT_Stroker_LineJoin line_join; 579*37da2899SCharles.Forsyth FT_Fixed miter_limit; 580*37da2899SCharles.Forsyth FT_Fixed radius; 581*37da2899SCharles.Forsyth 582*37da2899SCharles.Forsyth FT_Bool valid; 583*37da2899SCharles.Forsyth FT_StrokeBorderRec borders[2]; 584*37da2899SCharles.Forsyth FT_Memory memory; 585*37da2899SCharles.Forsyth 586*37da2899SCharles.Forsyth } FT_StrokerRec; 587*37da2899SCharles.Forsyth 588*37da2899SCharles.Forsyth 589*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_New(FT_Memory memory,FT_Stroker * astroker)590*37da2899SCharles.Forsyth FT_Stroker_New( FT_Memory memory, 591*37da2899SCharles.Forsyth FT_Stroker *astroker ) 592*37da2899SCharles.Forsyth { 593*37da2899SCharles.Forsyth FT_Error error; 594*37da2899SCharles.Forsyth FT_Stroker stroker; 595*37da2899SCharles.Forsyth 596*37da2899SCharles.Forsyth if ( !FT_NEW( stroker ) ) 597*37da2899SCharles.Forsyth { 598*37da2899SCharles.Forsyth stroker->memory = memory; 599*37da2899SCharles.Forsyth 600*37da2899SCharles.Forsyth ft_stroke_border_init( &stroker->borders[0], memory ); 601*37da2899SCharles.Forsyth ft_stroke_border_init( &stroker->borders[1], memory ); 602*37da2899SCharles.Forsyth } 603*37da2899SCharles.Forsyth *astroker = stroker; 604*37da2899SCharles.Forsyth return error; 605*37da2899SCharles.Forsyth } 606*37da2899SCharles.Forsyth 607*37da2899SCharles.Forsyth 608*37da2899SCharles.Forsyth 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)609*37da2899SCharles.Forsyth FT_Stroker_Set( FT_Stroker stroker, 610*37da2899SCharles.Forsyth FT_Fixed radius, 611*37da2899SCharles.Forsyth FT_Stroker_LineCap line_cap, 612*37da2899SCharles.Forsyth FT_Stroker_LineJoin line_join, 613*37da2899SCharles.Forsyth FT_Fixed miter_limit ) 614*37da2899SCharles.Forsyth { 615*37da2899SCharles.Forsyth stroker->radius = radius; 616*37da2899SCharles.Forsyth stroker->line_cap = line_cap; 617*37da2899SCharles.Forsyth stroker->line_join = line_join; 618*37da2899SCharles.Forsyth stroker->miter_limit = miter_limit; 619*37da2899SCharles.Forsyth 620*37da2899SCharles.Forsyth stroker->valid = 0; 621*37da2899SCharles.Forsyth 622*37da2899SCharles.Forsyth ft_stroke_border_reset( &stroker->borders[0] ); 623*37da2899SCharles.Forsyth ft_stroke_border_reset( &stroker->borders[1] ); 624*37da2899SCharles.Forsyth } 625*37da2899SCharles.Forsyth 626*37da2899SCharles.Forsyth 627*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_Stroker_Done(FT_Stroker stroker)628*37da2899SCharles.Forsyth FT_Stroker_Done( FT_Stroker stroker ) 629*37da2899SCharles.Forsyth { 630*37da2899SCharles.Forsyth if ( stroker ) 631*37da2899SCharles.Forsyth { 632*37da2899SCharles.Forsyth FT_Memory memory = stroker->memory; 633*37da2899SCharles.Forsyth 634*37da2899SCharles.Forsyth ft_stroke_border_done( &stroker->borders[0] ); 635*37da2899SCharles.Forsyth ft_stroke_border_done( &stroker->borders[1] ); 636*37da2899SCharles.Forsyth 637*37da2899SCharles.Forsyth stroker->memory = NULL; 638*37da2899SCharles.Forsyth FT_FREE( stroker ); 639*37da2899SCharles.Forsyth } 640*37da2899SCharles.Forsyth } 641*37da2899SCharles.Forsyth 642*37da2899SCharles.Forsyth 643*37da2899SCharles.Forsyth 644*37da2899SCharles.Forsyth /* creates a circular arc at a corner or cap */ 645*37da2899SCharles.Forsyth static FT_Error ft_stroker_arcto(FT_Stroker stroker,FT_Int side)646*37da2899SCharles.Forsyth ft_stroker_arcto( FT_Stroker stroker, 647*37da2899SCharles.Forsyth FT_Int side ) 648*37da2899SCharles.Forsyth { 649*37da2899SCharles.Forsyth FT_Angle total, rotate; 650*37da2899SCharles.Forsyth FT_Fixed radius = stroker->radius; 651*37da2899SCharles.Forsyth FT_Error error = 0; 652*37da2899SCharles.Forsyth FT_StrokeBorder border = stroker->borders + side; 653*37da2899SCharles.Forsyth 654*37da2899SCharles.Forsyth rotate = FT_SIDE_TO_ROTATE(side); 655*37da2899SCharles.Forsyth 656*37da2899SCharles.Forsyth total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 657*37da2899SCharles.Forsyth if (total == FT_ANGLE_PI) 658*37da2899SCharles.Forsyth total = -rotate*2; 659*37da2899SCharles.Forsyth 660*37da2899SCharles.Forsyth error = ft_stroke_border_arcto( border, 661*37da2899SCharles.Forsyth &stroker->center, 662*37da2899SCharles.Forsyth radius, 663*37da2899SCharles.Forsyth stroker->angle_in + rotate, 664*37da2899SCharles.Forsyth total ); 665*37da2899SCharles.Forsyth border->movable = 0; 666*37da2899SCharles.Forsyth return error; 667*37da2899SCharles.Forsyth } 668*37da2899SCharles.Forsyth 669*37da2899SCharles.Forsyth 670*37da2899SCharles.Forsyth /* adds a cap at the end of an opened path */ 671*37da2899SCharles.Forsyth static FT_Error ft_stroker_cap(FT_Stroker stroker,FT_Angle angle,FT_Int side)672*37da2899SCharles.Forsyth ft_stroker_cap( FT_Stroker stroker, 673*37da2899SCharles.Forsyth FT_Angle angle, 674*37da2899SCharles.Forsyth FT_Int side ) 675*37da2899SCharles.Forsyth { 676*37da2899SCharles.Forsyth FT_Error error = 0; 677*37da2899SCharles.Forsyth 678*37da2899SCharles.Forsyth if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) 679*37da2899SCharles.Forsyth { 680*37da2899SCharles.Forsyth /* add a round cap */ 681*37da2899SCharles.Forsyth stroker->angle_in = angle; 682*37da2899SCharles.Forsyth stroker->angle_out = angle + FT_ANGLE_PI; 683*37da2899SCharles.Forsyth error = ft_stroker_arcto( stroker, side ); 684*37da2899SCharles.Forsyth } 685*37da2899SCharles.Forsyth else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) 686*37da2899SCharles.Forsyth { 687*37da2899SCharles.Forsyth /* add a square cap */ 688*37da2899SCharles.Forsyth FT_Vector delta, delta2; 689*37da2899SCharles.Forsyth FT_Angle rotate = FT_SIDE_TO_ROTATE(side); 690*37da2899SCharles.Forsyth FT_Fixed radius = stroker->radius; 691*37da2899SCharles.Forsyth FT_StrokeBorder border = stroker->borders + side; 692*37da2899SCharles.Forsyth 693*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta2, radius, angle+rotate ); 694*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, radius, angle ); 695*37da2899SCharles.Forsyth 696*37da2899SCharles.Forsyth delta.x += stroker->center.x + delta2.x; 697*37da2899SCharles.Forsyth delta.y += stroker->center.y + delta2.y; 698*37da2899SCharles.Forsyth 699*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 700*37da2899SCharles.Forsyth if (error) goto Exit; 701*37da2899SCharles.Forsyth 702*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta2, radius, angle-rotate ); 703*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, radius, angle ); 704*37da2899SCharles.Forsyth 705*37da2899SCharles.Forsyth delta.x += delta2.x + stroker->center.x; 706*37da2899SCharles.Forsyth delta.y += delta2.y + stroker->center.y; 707*37da2899SCharles.Forsyth 708*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 709*37da2899SCharles.Forsyth } 710*37da2899SCharles.Forsyth Exit: 711*37da2899SCharles.Forsyth return error; 712*37da2899SCharles.Forsyth } 713*37da2899SCharles.Forsyth 714*37da2899SCharles.Forsyth 715*37da2899SCharles.Forsyth 716*37da2899SCharles.Forsyth /* process an inside corner, i.e. compute intersection */ 717*37da2899SCharles.Forsyth static FT_Error ft_stroker_inside(FT_Stroker stroker,FT_Int side)718*37da2899SCharles.Forsyth ft_stroker_inside( FT_Stroker stroker, 719*37da2899SCharles.Forsyth FT_Int side) 720*37da2899SCharles.Forsyth { 721*37da2899SCharles.Forsyth FT_StrokeBorder border = stroker->borders + side; 722*37da2899SCharles.Forsyth FT_Angle phi, theta, rotate; 723*37da2899SCharles.Forsyth FT_Fixed length, thcos, sigma; 724*37da2899SCharles.Forsyth FT_Vector delta; 725*37da2899SCharles.Forsyth FT_Error error = 0; 726*37da2899SCharles.Forsyth 727*37da2899SCharles.Forsyth 728*37da2899SCharles.Forsyth rotate = FT_SIDE_TO_ROTATE(side); 729*37da2899SCharles.Forsyth 730*37da2899SCharles.Forsyth /* compute median angle */ 731*37da2899SCharles.Forsyth theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 732*37da2899SCharles.Forsyth if ( theta == FT_ANGLE_PI ) 733*37da2899SCharles.Forsyth theta = rotate; 734*37da2899SCharles.Forsyth else 735*37da2899SCharles.Forsyth theta = theta/2; 736*37da2899SCharles.Forsyth 737*37da2899SCharles.Forsyth phi = stroker->angle_in + theta; 738*37da2899SCharles.Forsyth 739*37da2899SCharles.Forsyth thcos = FT_Cos( theta ); 740*37da2899SCharles.Forsyth sigma = FT_MulFix( stroker->miter_limit, thcos ); 741*37da2899SCharles.Forsyth 742*37da2899SCharles.Forsyth if ( sigma < 0x10000L ) 743*37da2899SCharles.Forsyth { 744*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate ); 745*37da2899SCharles.Forsyth delta.x += stroker->center.x; 746*37da2899SCharles.Forsyth delta.y += stroker->center.y; 747*37da2899SCharles.Forsyth border->movable = 0; 748*37da2899SCharles.Forsyth } 749*37da2899SCharles.Forsyth else 750*37da2899SCharles.Forsyth { 751*37da2899SCharles.Forsyth length = FT_DivFix( stroker->radius, thcos ); 752*37da2899SCharles.Forsyth 753*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, length, phi + rotate ); 754*37da2899SCharles.Forsyth delta.x += stroker->center.x; 755*37da2899SCharles.Forsyth delta.y += stroker->center.y; 756*37da2899SCharles.Forsyth } 757*37da2899SCharles.Forsyth 758*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 759*37da2899SCharles.Forsyth 760*37da2899SCharles.Forsyth return error; 761*37da2899SCharles.Forsyth } 762*37da2899SCharles.Forsyth 763*37da2899SCharles.Forsyth 764*37da2899SCharles.Forsyth /* process an outside corner, i.e. compute bevel/miter/round */ 765*37da2899SCharles.Forsyth static FT_Error ft_stroker_outside(FT_Stroker stroker,FT_Int side)766*37da2899SCharles.Forsyth ft_stroker_outside( FT_Stroker stroker, 767*37da2899SCharles.Forsyth FT_Int side ) 768*37da2899SCharles.Forsyth { 769*37da2899SCharles.Forsyth FT_StrokeBorder border = stroker->borders + side; 770*37da2899SCharles.Forsyth FT_Error error; 771*37da2899SCharles.Forsyth FT_Angle rotate; 772*37da2899SCharles.Forsyth 773*37da2899SCharles.Forsyth if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) 774*37da2899SCharles.Forsyth { 775*37da2899SCharles.Forsyth error = ft_stroker_arcto( stroker, side ); 776*37da2899SCharles.Forsyth } 777*37da2899SCharles.Forsyth else 778*37da2899SCharles.Forsyth { 779*37da2899SCharles.Forsyth /* this is a mitered or beveled corner */ 780*37da2899SCharles.Forsyth FT_Fixed sigma, radius = stroker->radius; 781*37da2899SCharles.Forsyth FT_Angle theta, phi; 782*37da2899SCharles.Forsyth FT_Fixed thcos; 783*37da2899SCharles.Forsyth FT_Bool miter; 784*37da2899SCharles.Forsyth 785*37da2899SCharles.Forsyth rotate = FT_SIDE_TO_ROTATE(side); 786*37da2899SCharles.Forsyth miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER ); 787*37da2899SCharles.Forsyth 788*37da2899SCharles.Forsyth theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 789*37da2899SCharles.Forsyth if (theta == FT_ANGLE_PI) 790*37da2899SCharles.Forsyth theta = rotate; 791*37da2899SCharles.Forsyth else 792*37da2899SCharles.Forsyth theta = theta/2; 793*37da2899SCharles.Forsyth 794*37da2899SCharles.Forsyth thcos = FT_Cos( theta ); 795*37da2899SCharles.Forsyth sigma = FT_MulFix( stroker->miter_limit, thcos ); 796*37da2899SCharles.Forsyth 797*37da2899SCharles.Forsyth if ( sigma >= 0x10000L ) 798*37da2899SCharles.Forsyth miter = 0; 799*37da2899SCharles.Forsyth 800*37da2899SCharles.Forsyth phi = stroker->angle_in + theta + rotate; 801*37da2899SCharles.Forsyth 802*37da2899SCharles.Forsyth if (miter) /* this is a miter (broken angle) */ 803*37da2899SCharles.Forsyth { 804*37da2899SCharles.Forsyth FT_Vector middle, delta; 805*37da2899SCharles.Forsyth FT_Fixed length; 806*37da2899SCharles.Forsyth 807*37da2899SCharles.Forsyth /* compute middle point */ 808*37da2899SCharles.Forsyth FT_Vector_From_Polar( &middle, FT_MulFix( radius, stroker->miter_limit ), 809*37da2899SCharles.Forsyth phi ); 810*37da2899SCharles.Forsyth middle.x += stroker->center.x; 811*37da2899SCharles.Forsyth middle.y += stroker->center.y; 812*37da2899SCharles.Forsyth 813*37da2899SCharles.Forsyth /* compute first angle point */ 814*37da2899SCharles.Forsyth length = FT_MulFix( radius, FT_DivFix( 0x10000L - sigma, 815*37da2899SCharles.Forsyth ft_pos_abs( FT_Sin( theta ) ) ) ); 816*37da2899SCharles.Forsyth 817*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, length, phi + rotate ); 818*37da2899SCharles.Forsyth delta.x += middle.x; 819*37da2899SCharles.Forsyth delta.y += middle.y; 820*37da2899SCharles.Forsyth 821*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 822*37da2899SCharles.Forsyth if (error) goto Exit; 823*37da2899SCharles.Forsyth 824*37da2899SCharles.Forsyth /* compute second angle point */ 825*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, length, phi - rotate ); 826*37da2899SCharles.Forsyth delta.x += middle.x; 827*37da2899SCharles.Forsyth delta.y += middle.y; 828*37da2899SCharles.Forsyth 829*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 830*37da2899SCharles.Forsyth if (error) goto Exit; 831*37da2899SCharles.Forsyth 832*37da2899SCharles.Forsyth /* finally, add a movable end point */ 833*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate ); 834*37da2899SCharles.Forsyth delta.x += stroker->center.x; 835*37da2899SCharles.Forsyth delta.y += stroker->center.y; 836*37da2899SCharles.Forsyth 837*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 1 ); 838*37da2899SCharles.Forsyth } 839*37da2899SCharles.Forsyth else /* this is a bevel (intersection) */ 840*37da2899SCharles.Forsyth { 841*37da2899SCharles.Forsyth FT_Fixed length; 842*37da2899SCharles.Forsyth FT_Vector delta; 843*37da2899SCharles.Forsyth 844*37da2899SCharles.Forsyth length = FT_DivFix( stroker->radius, thcos ); 845*37da2899SCharles.Forsyth 846*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, length, phi ); 847*37da2899SCharles.Forsyth delta.x += stroker->center.x; 848*37da2899SCharles.Forsyth delta.y += stroker->center.y; 849*37da2899SCharles.Forsyth 850*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 0 ); 851*37da2899SCharles.Forsyth if (error) goto Exit; 852*37da2899SCharles.Forsyth 853*37da2899SCharles.Forsyth /* now add end point */ 854*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate ); 855*37da2899SCharles.Forsyth delta.x += stroker->center.x; 856*37da2899SCharles.Forsyth delta.y += stroker->center.y; 857*37da2899SCharles.Forsyth 858*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &delta, 1 ); 859*37da2899SCharles.Forsyth } 860*37da2899SCharles.Forsyth } 861*37da2899SCharles.Forsyth Exit: 862*37da2899SCharles.Forsyth return error; 863*37da2899SCharles.Forsyth } 864*37da2899SCharles.Forsyth 865*37da2899SCharles.Forsyth 866*37da2899SCharles.Forsyth static FT_Error ft_stroker_process_corner(FT_Stroker stroker)867*37da2899SCharles.Forsyth ft_stroker_process_corner( FT_Stroker stroker ) 868*37da2899SCharles.Forsyth { 869*37da2899SCharles.Forsyth FT_Error error = 0; 870*37da2899SCharles.Forsyth FT_Angle turn; 871*37da2899SCharles.Forsyth FT_Int inside_side; 872*37da2899SCharles.Forsyth 873*37da2899SCharles.Forsyth turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 874*37da2899SCharles.Forsyth 875*37da2899SCharles.Forsyth /* no specific corner processing is required if the turn is 0 */ 876*37da2899SCharles.Forsyth if (turn == 0) 877*37da2899SCharles.Forsyth goto Exit; 878*37da2899SCharles.Forsyth 879*37da2899SCharles.Forsyth /* when we turn to the right, the inside side is 0 */ 880*37da2899SCharles.Forsyth inside_side = 0; 881*37da2899SCharles.Forsyth 882*37da2899SCharles.Forsyth /* otherwise, the inside side is 1 */ 883*37da2899SCharles.Forsyth if (turn < 0) 884*37da2899SCharles.Forsyth inside_side = 1; 885*37da2899SCharles.Forsyth 886*37da2899SCharles.Forsyth /* process the inside side */ 887*37da2899SCharles.Forsyth error = ft_stroker_inside( stroker, inside_side ); 888*37da2899SCharles.Forsyth if (error) goto Exit; 889*37da2899SCharles.Forsyth 890*37da2899SCharles.Forsyth /* process the outside side */ 891*37da2899SCharles.Forsyth error = ft_stroker_outside( stroker, 1-inside_side ); 892*37da2899SCharles.Forsyth 893*37da2899SCharles.Forsyth Exit: 894*37da2899SCharles.Forsyth return error; 895*37da2899SCharles.Forsyth } 896*37da2899SCharles.Forsyth 897*37da2899SCharles.Forsyth 898*37da2899SCharles.Forsyth /* add two points to the left and right borders corresponding to the */ 899*37da2899SCharles.Forsyth /* start of the subpath.. */ 900*37da2899SCharles.Forsyth static FT_Error ft_stroker_subpath_start(FT_Stroker stroker,FT_Angle start_angle)901*37da2899SCharles.Forsyth ft_stroker_subpath_start( FT_Stroker stroker, 902*37da2899SCharles.Forsyth FT_Angle start_angle ) 903*37da2899SCharles.Forsyth { 904*37da2899SCharles.Forsyth FT_Vector delta; 905*37da2899SCharles.Forsyth FT_Vector point; 906*37da2899SCharles.Forsyth FT_Error error; 907*37da2899SCharles.Forsyth FT_StrokeBorder border; 908*37da2899SCharles.Forsyth 909*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, stroker->radius, start_angle + FT_ANGLE_PI2 ); 910*37da2899SCharles.Forsyth 911*37da2899SCharles.Forsyth point.x = stroker->center.x + delta.x; 912*37da2899SCharles.Forsyth point.y = stroker->center.y + delta.y; 913*37da2899SCharles.Forsyth 914*37da2899SCharles.Forsyth border = stroker->borders; 915*37da2899SCharles.Forsyth error = ft_stroke_border_moveto( border, &point ); 916*37da2899SCharles.Forsyth if (error) goto Exit; 917*37da2899SCharles.Forsyth 918*37da2899SCharles.Forsyth point.x = stroker->center.x - delta.x; 919*37da2899SCharles.Forsyth point.y = stroker->center.y - delta.y; 920*37da2899SCharles.Forsyth 921*37da2899SCharles.Forsyth border++; 922*37da2899SCharles.Forsyth error = ft_stroke_border_moveto( border, &point ); 923*37da2899SCharles.Forsyth 924*37da2899SCharles.Forsyth /* save angle for last cap */ 925*37da2899SCharles.Forsyth stroker->subpath_angle = start_angle; 926*37da2899SCharles.Forsyth stroker->first_point = 0; 927*37da2899SCharles.Forsyth 928*37da2899SCharles.Forsyth Exit: 929*37da2899SCharles.Forsyth return error; 930*37da2899SCharles.Forsyth } 931*37da2899SCharles.Forsyth 932*37da2899SCharles.Forsyth 933*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_LineTo(FT_Stroker stroker,FT_Vector * to)934*37da2899SCharles.Forsyth FT_Stroker_LineTo( FT_Stroker stroker, 935*37da2899SCharles.Forsyth FT_Vector* to ) 936*37da2899SCharles.Forsyth { 937*37da2899SCharles.Forsyth FT_Error error = 0; 938*37da2899SCharles.Forsyth FT_StrokeBorder border; 939*37da2899SCharles.Forsyth FT_Vector delta; 940*37da2899SCharles.Forsyth FT_Angle angle; 941*37da2899SCharles.Forsyth FT_Int side; 942*37da2899SCharles.Forsyth 943*37da2899SCharles.Forsyth delta.x = to->x - stroker->center.x; 944*37da2899SCharles.Forsyth delta.y = to->y - stroker->center.y; 945*37da2899SCharles.Forsyth 946*37da2899SCharles.Forsyth angle = FT_Atan2( delta.x, delta.y ); 947*37da2899SCharles.Forsyth FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); 948*37da2899SCharles.Forsyth 949*37da2899SCharles.Forsyth /* process corner if necessary */ 950*37da2899SCharles.Forsyth if ( stroker->first_point ) 951*37da2899SCharles.Forsyth { 952*37da2899SCharles.Forsyth /* this is the first segment of a subpath. We need to */ 953*37da2899SCharles.Forsyth /* add a point to each border at their respective starting */ 954*37da2899SCharles.Forsyth /* point locations.. */ 955*37da2899SCharles.Forsyth error = ft_stroker_subpath_start( stroker, angle ); 956*37da2899SCharles.Forsyth if (error) goto Exit; 957*37da2899SCharles.Forsyth } 958*37da2899SCharles.Forsyth else 959*37da2899SCharles.Forsyth { 960*37da2899SCharles.Forsyth /* process the current corner */ 961*37da2899SCharles.Forsyth stroker->angle_out = angle; 962*37da2899SCharles.Forsyth error = ft_stroker_process_corner( stroker ); 963*37da2899SCharles.Forsyth if (error) goto Exit; 964*37da2899SCharles.Forsyth } 965*37da2899SCharles.Forsyth 966*37da2899SCharles.Forsyth /* now add a line segment to both the "inside" and "outside" paths */ 967*37da2899SCharles.Forsyth 968*37da2899SCharles.Forsyth for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) 969*37da2899SCharles.Forsyth { 970*37da2899SCharles.Forsyth FT_Vector point; 971*37da2899SCharles.Forsyth 972*37da2899SCharles.Forsyth point.x = to->x + delta.x; 973*37da2899SCharles.Forsyth point.y = to->y + delta.y; 974*37da2899SCharles.Forsyth 975*37da2899SCharles.Forsyth error = ft_stroke_border_lineto( border, &point, 1 ); 976*37da2899SCharles.Forsyth if (error) goto Exit; 977*37da2899SCharles.Forsyth 978*37da2899SCharles.Forsyth delta.x = -delta.x; 979*37da2899SCharles.Forsyth delta.y = -delta.y; 980*37da2899SCharles.Forsyth } 981*37da2899SCharles.Forsyth 982*37da2899SCharles.Forsyth stroker->angle_in = angle; 983*37da2899SCharles.Forsyth stroker->center = *to; 984*37da2899SCharles.Forsyth 985*37da2899SCharles.Forsyth Exit: 986*37da2899SCharles.Forsyth return error; 987*37da2899SCharles.Forsyth } 988*37da2899SCharles.Forsyth 989*37da2899SCharles.Forsyth 990*37da2899SCharles.Forsyth 991*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_ConicTo(FT_Stroker stroker,FT_Vector * control,FT_Vector * to)992*37da2899SCharles.Forsyth FT_Stroker_ConicTo( FT_Stroker stroker, 993*37da2899SCharles.Forsyth FT_Vector* control, 994*37da2899SCharles.Forsyth FT_Vector* to ) 995*37da2899SCharles.Forsyth { 996*37da2899SCharles.Forsyth FT_Error error = 0; 997*37da2899SCharles.Forsyth FT_Vector bez_stack[34]; 998*37da2899SCharles.Forsyth FT_Vector* arc; 999*37da2899SCharles.Forsyth FT_Vector* limit = bez_stack + 30; 1000*37da2899SCharles.Forsyth FT_Angle start_angle; 1001*37da2899SCharles.Forsyth FT_Bool first_arc = 1; 1002*37da2899SCharles.Forsyth 1003*37da2899SCharles.Forsyth arc = bez_stack; 1004*37da2899SCharles.Forsyth arc[0] = *to; 1005*37da2899SCharles.Forsyth arc[1] = *control; 1006*37da2899SCharles.Forsyth arc[2] = stroker->center; 1007*37da2899SCharles.Forsyth 1008*37da2899SCharles.Forsyth while ( arc >= bez_stack ) 1009*37da2899SCharles.Forsyth { 1010*37da2899SCharles.Forsyth FT_Angle angle_in, angle_out; 1011*37da2899SCharles.Forsyth 1012*37da2899SCharles.Forsyth angle_in = angle_out = 0; /* remove compiler warnings */ 1013*37da2899SCharles.Forsyth 1014*37da2899SCharles.Forsyth if ( arc < limit && 1015*37da2899SCharles.Forsyth !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) 1016*37da2899SCharles.Forsyth { 1017*37da2899SCharles.Forsyth ft_conic_split( arc ); 1018*37da2899SCharles.Forsyth arc += 2; 1019*37da2899SCharles.Forsyth continue; 1020*37da2899SCharles.Forsyth } 1021*37da2899SCharles.Forsyth 1022*37da2899SCharles.Forsyth if ( first_arc ) 1023*37da2899SCharles.Forsyth { 1024*37da2899SCharles.Forsyth first_arc = 0; 1025*37da2899SCharles.Forsyth 1026*37da2899SCharles.Forsyth start_angle = angle_in; 1027*37da2899SCharles.Forsyth 1028*37da2899SCharles.Forsyth /* process corner if necessary */ 1029*37da2899SCharles.Forsyth if ( stroker->first_point ) 1030*37da2899SCharles.Forsyth error = ft_stroker_subpath_start( stroker, start_angle ); 1031*37da2899SCharles.Forsyth else 1032*37da2899SCharles.Forsyth { 1033*37da2899SCharles.Forsyth stroker->angle_out = start_angle; 1034*37da2899SCharles.Forsyth error = ft_stroker_process_corner( stroker ); 1035*37da2899SCharles.Forsyth } 1036*37da2899SCharles.Forsyth } 1037*37da2899SCharles.Forsyth 1038*37da2899SCharles.Forsyth /* the arc's angle is small enough, we can add it directly to each */ 1039*37da2899SCharles.Forsyth /* border.. */ 1040*37da2899SCharles.Forsyth { 1041*37da2899SCharles.Forsyth FT_Vector ctrl, end; 1042*37da2899SCharles.Forsyth FT_Angle theta, phi, rotate; 1043*37da2899SCharles.Forsyth FT_Fixed length; 1044*37da2899SCharles.Forsyth FT_Int side; 1045*37da2899SCharles.Forsyth 1046*37da2899SCharles.Forsyth theta = FT_Angle_Diff( angle_in, angle_out )/2; 1047*37da2899SCharles.Forsyth phi = angle_in + theta; 1048*37da2899SCharles.Forsyth length = FT_DivFix( stroker->radius, FT_Cos(theta) ); 1049*37da2899SCharles.Forsyth 1050*37da2899SCharles.Forsyth for ( side = 0; side <= 1; side++ ) 1051*37da2899SCharles.Forsyth { 1052*37da2899SCharles.Forsyth rotate = FT_SIDE_TO_ROTATE(side); 1053*37da2899SCharles.Forsyth 1054*37da2899SCharles.Forsyth /* compute control point */ 1055*37da2899SCharles.Forsyth FT_Vector_From_Polar( &ctrl, length, phi + rotate ); 1056*37da2899SCharles.Forsyth ctrl.x += arc[1].x; 1057*37da2899SCharles.Forsyth ctrl.y += arc[1].y; 1058*37da2899SCharles.Forsyth 1059*37da2899SCharles.Forsyth /* compute end point */ 1060*37da2899SCharles.Forsyth FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); 1061*37da2899SCharles.Forsyth end.x += arc[0].x; 1062*37da2899SCharles.Forsyth end.y += arc[0].y; 1063*37da2899SCharles.Forsyth 1064*37da2899SCharles.Forsyth error = ft_stroke_border_conicto( stroker->borders + side, &ctrl, &end ); 1065*37da2899SCharles.Forsyth if (error) goto Exit; 1066*37da2899SCharles.Forsyth } 1067*37da2899SCharles.Forsyth } 1068*37da2899SCharles.Forsyth 1069*37da2899SCharles.Forsyth arc -= 2; 1070*37da2899SCharles.Forsyth 1071*37da2899SCharles.Forsyth if (arc < bez_stack) 1072*37da2899SCharles.Forsyth stroker->angle_in = angle_out; 1073*37da2899SCharles.Forsyth } 1074*37da2899SCharles.Forsyth 1075*37da2899SCharles.Forsyth stroker->center = *to; 1076*37da2899SCharles.Forsyth 1077*37da2899SCharles.Forsyth Exit: 1078*37da2899SCharles.Forsyth return error; 1079*37da2899SCharles.Forsyth } 1080*37da2899SCharles.Forsyth 1081*37da2899SCharles.Forsyth 1082*37da2899SCharles.Forsyth 1083*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_CubicTo(FT_Stroker stroker,FT_Vector * control1,FT_Vector * control2,FT_Vector * to)1084*37da2899SCharles.Forsyth FT_Stroker_CubicTo( FT_Stroker stroker, 1085*37da2899SCharles.Forsyth FT_Vector* control1, 1086*37da2899SCharles.Forsyth FT_Vector* control2, 1087*37da2899SCharles.Forsyth FT_Vector* to ) 1088*37da2899SCharles.Forsyth { 1089*37da2899SCharles.Forsyth FT_Error error = 0; 1090*37da2899SCharles.Forsyth FT_Vector bez_stack[37]; 1091*37da2899SCharles.Forsyth FT_Vector* arc; 1092*37da2899SCharles.Forsyth FT_Vector* limit = bez_stack + 32; 1093*37da2899SCharles.Forsyth FT_Angle start_angle; 1094*37da2899SCharles.Forsyth FT_Bool first_arc = 1; 1095*37da2899SCharles.Forsyth 1096*37da2899SCharles.Forsyth arc = bez_stack; 1097*37da2899SCharles.Forsyth arc[0] = *to; 1098*37da2899SCharles.Forsyth arc[1] = *control2; 1099*37da2899SCharles.Forsyth arc[2] = *control1; 1100*37da2899SCharles.Forsyth arc[3] = stroker->center; 1101*37da2899SCharles.Forsyth 1102*37da2899SCharles.Forsyth while ( arc >= bez_stack ) 1103*37da2899SCharles.Forsyth { 1104*37da2899SCharles.Forsyth FT_Angle angle_in, angle_mid, angle_out; 1105*37da2899SCharles.Forsyth 1106*37da2899SCharles.Forsyth /* remove compiler warnings */ 1107*37da2899SCharles.Forsyth angle_in = angle_out = angle_mid = 0; 1108*37da2899SCharles.Forsyth 1109*37da2899SCharles.Forsyth if ( arc < limit && 1110*37da2899SCharles.Forsyth !ft_cubic_is_small_enough( arc, &angle_in, &angle_mid, &angle_out ) ) 1111*37da2899SCharles.Forsyth { 1112*37da2899SCharles.Forsyth ft_cubic_split( arc ); 1113*37da2899SCharles.Forsyth arc += 3; 1114*37da2899SCharles.Forsyth continue; 1115*37da2899SCharles.Forsyth } 1116*37da2899SCharles.Forsyth 1117*37da2899SCharles.Forsyth if ( first_arc ) 1118*37da2899SCharles.Forsyth { 1119*37da2899SCharles.Forsyth first_arc = 0; 1120*37da2899SCharles.Forsyth 1121*37da2899SCharles.Forsyth /* process corner if necessary */ 1122*37da2899SCharles.Forsyth start_angle = angle_in; 1123*37da2899SCharles.Forsyth 1124*37da2899SCharles.Forsyth if ( stroker->first_point ) 1125*37da2899SCharles.Forsyth error = ft_stroker_subpath_start( stroker, start_angle ); 1126*37da2899SCharles.Forsyth else 1127*37da2899SCharles.Forsyth { 1128*37da2899SCharles.Forsyth stroker->angle_out = start_angle; 1129*37da2899SCharles.Forsyth error = ft_stroker_process_corner( stroker ); 1130*37da2899SCharles.Forsyth } 1131*37da2899SCharles.Forsyth if (error) goto Exit; 1132*37da2899SCharles.Forsyth } 1133*37da2899SCharles.Forsyth 1134*37da2899SCharles.Forsyth /* the arc's angle is small enough, we can add it directly to each */ 1135*37da2899SCharles.Forsyth /* border.. */ 1136*37da2899SCharles.Forsyth { 1137*37da2899SCharles.Forsyth FT_Vector ctrl1, ctrl2, end; 1138*37da2899SCharles.Forsyth FT_Angle theta1, phi1, theta2, phi2, rotate; 1139*37da2899SCharles.Forsyth FT_Fixed length1, length2; 1140*37da2899SCharles.Forsyth FT_Int side; 1141*37da2899SCharles.Forsyth 1142*37da2899SCharles.Forsyth theta1 = ft_pos_abs( angle_mid - angle_in )/2; 1143*37da2899SCharles.Forsyth theta2 = ft_pos_abs( angle_out - angle_mid )/2; 1144*37da2899SCharles.Forsyth phi1 = (angle_mid+angle_in)/2; 1145*37da2899SCharles.Forsyth phi2 = (angle_mid+angle_out)/2; 1146*37da2899SCharles.Forsyth length1 = FT_DivFix( stroker->radius, FT_Cos(theta1) ); 1147*37da2899SCharles.Forsyth length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) ); 1148*37da2899SCharles.Forsyth 1149*37da2899SCharles.Forsyth for ( side = 0; side <= 1; side++ ) 1150*37da2899SCharles.Forsyth { 1151*37da2899SCharles.Forsyth rotate = FT_SIDE_TO_ROTATE(side); 1152*37da2899SCharles.Forsyth 1153*37da2899SCharles.Forsyth /* compute control points */ 1154*37da2899SCharles.Forsyth FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); 1155*37da2899SCharles.Forsyth ctrl1.x += arc[2].x; 1156*37da2899SCharles.Forsyth ctrl1.y += arc[2].y; 1157*37da2899SCharles.Forsyth 1158*37da2899SCharles.Forsyth FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); 1159*37da2899SCharles.Forsyth ctrl2.x += arc[1].x; 1160*37da2899SCharles.Forsyth ctrl2.y += arc[1].y; 1161*37da2899SCharles.Forsyth 1162*37da2899SCharles.Forsyth /* compute end point */ 1163*37da2899SCharles.Forsyth FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); 1164*37da2899SCharles.Forsyth end.x += arc[0].x; 1165*37da2899SCharles.Forsyth end.y += arc[0].y; 1166*37da2899SCharles.Forsyth 1167*37da2899SCharles.Forsyth error = ft_stroke_border_cubicto( stroker->borders + side, &ctrl1, &ctrl2, &end ); 1168*37da2899SCharles.Forsyth if (error) goto Exit; 1169*37da2899SCharles.Forsyth } 1170*37da2899SCharles.Forsyth } 1171*37da2899SCharles.Forsyth 1172*37da2899SCharles.Forsyth arc -= 3; 1173*37da2899SCharles.Forsyth if (arc < bez_stack) 1174*37da2899SCharles.Forsyth stroker->angle_in = angle_out; 1175*37da2899SCharles.Forsyth } 1176*37da2899SCharles.Forsyth 1177*37da2899SCharles.Forsyth stroker->center = *to; 1178*37da2899SCharles.Forsyth 1179*37da2899SCharles.Forsyth Exit: 1180*37da2899SCharles.Forsyth return error; 1181*37da2899SCharles.Forsyth } 1182*37da2899SCharles.Forsyth 1183*37da2899SCharles.Forsyth 1184*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_BeginSubPath(FT_Stroker stroker,FT_Vector * to,FT_Bool open)1185*37da2899SCharles.Forsyth FT_Stroker_BeginSubPath( FT_Stroker stroker, 1186*37da2899SCharles.Forsyth FT_Vector* to, 1187*37da2899SCharles.Forsyth FT_Bool open ) 1188*37da2899SCharles.Forsyth { 1189*37da2899SCharles.Forsyth /* we cannot process the first point, because there is not enough */ 1190*37da2899SCharles.Forsyth /* information regarding its corner/cap. The latter will be processed */ 1191*37da2899SCharles.Forsyth /* in the "end_subpath" routine */ 1192*37da2899SCharles.Forsyth /* */ 1193*37da2899SCharles.Forsyth stroker->first_point = 1; 1194*37da2899SCharles.Forsyth stroker->center = *to; 1195*37da2899SCharles.Forsyth stroker->subpath_open = open; 1196*37da2899SCharles.Forsyth 1197*37da2899SCharles.Forsyth /* record the subpath start point index for each border */ 1198*37da2899SCharles.Forsyth stroker->subpath_start = *to; 1199*37da2899SCharles.Forsyth return 0; 1200*37da2899SCharles.Forsyth } 1201*37da2899SCharles.Forsyth 1202*37da2899SCharles.Forsyth 1203*37da2899SCharles.Forsyth static ft_stroker_add_reverse_left(FT_Stroker stroker,FT_Bool open)1204*37da2899SCharles.Forsyth FT_Error ft_stroker_add_reverse_left( FT_Stroker stroker, 1205*37da2899SCharles.Forsyth FT_Bool open ) 1206*37da2899SCharles.Forsyth { 1207*37da2899SCharles.Forsyth FT_StrokeBorder right = stroker->borders + 0; 1208*37da2899SCharles.Forsyth FT_StrokeBorder left = stroker->borders + 1; 1209*37da2899SCharles.Forsyth FT_Int new_points; 1210*37da2899SCharles.Forsyth FT_Error error = 0; 1211*37da2899SCharles.Forsyth 1212*37da2899SCharles.Forsyth FT_ASSERT( left->start >= 0 ); 1213*37da2899SCharles.Forsyth 1214*37da2899SCharles.Forsyth new_points = left->num_points - left->start; 1215*37da2899SCharles.Forsyth if ( new_points > 0 ) 1216*37da2899SCharles.Forsyth { 1217*37da2899SCharles.Forsyth error = ft_stroke_border_grow( right, (FT_UInt)new_points ); 1218*37da2899SCharles.Forsyth if (error) goto Exit; 1219*37da2899SCharles.Forsyth { 1220*37da2899SCharles.Forsyth FT_Vector* dst_point = right->points + right->num_points; 1221*37da2899SCharles.Forsyth FT_Byte* dst_tag = right->tags + right->num_points; 1222*37da2899SCharles.Forsyth FT_Vector* src_point = left->points + left->num_points - 1; 1223*37da2899SCharles.Forsyth FT_Byte* src_tag = left->tags + left->num_points - 1; 1224*37da2899SCharles.Forsyth 1225*37da2899SCharles.Forsyth while ( src_point >= left->points + left->start ) 1226*37da2899SCharles.Forsyth { 1227*37da2899SCharles.Forsyth *dst_point = *src_point; 1228*37da2899SCharles.Forsyth *dst_tag = *src_tag; 1229*37da2899SCharles.Forsyth 1230*37da2899SCharles.Forsyth if (open) 1231*37da2899SCharles.Forsyth dst_tag[0] &= ~(FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END); 1232*37da2899SCharles.Forsyth else 1233*37da2899SCharles.Forsyth { 1234*37da2899SCharles.Forsyth /* switch begin/end tags if necessary.. */ 1235*37da2899SCharles.Forsyth if (dst_tag[0] & (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END)) 1236*37da2899SCharles.Forsyth dst_tag[0] ^= (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END); 1237*37da2899SCharles.Forsyth } 1238*37da2899SCharles.Forsyth 1239*37da2899SCharles.Forsyth src_point--; 1240*37da2899SCharles.Forsyth src_tag--; 1241*37da2899SCharles.Forsyth dst_point++; 1242*37da2899SCharles.Forsyth dst_tag++; 1243*37da2899SCharles.Forsyth } 1244*37da2899SCharles.Forsyth } 1245*37da2899SCharles.Forsyth left->num_points = left->start; 1246*37da2899SCharles.Forsyth right->num_points += new_points; 1247*37da2899SCharles.Forsyth 1248*37da2899SCharles.Forsyth right->movable = 0; 1249*37da2899SCharles.Forsyth left->movable = 0; 1250*37da2899SCharles.Forsyth } 1251*37da2899SCharles.Forsyth Exit: 1252*37da2899SCharles.Forsyth return error; 1253*37da2899SCharles.Forsyth } 1254*37da2899SCharles.Forsyth 1255*37da2899SCharles.Forsyth 1256*37da2899SCharles.Forsyth /* there's a lot of magic in this function !! */ 1257*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_EndSubPath(FT_Stroker stroker)1258*37da2899SCharles.Forsyth FT_Stroker_EndSubPath( FT_Stroker stroker ) 1259*37da2899SCharles.Forsyth { 1260*37da2899SCharles.Forsyth FT_Error error = 0; 1261*37da2899SCharles.Forsyth 1262*37da2899SCharles.Forsyth if ( stroker->subpath_open ) 1263*37da2899SCharles.Forsyth { 1264*37da2899SCharles.Forsyth FT_StrokeBorder right = stroker->borders; 1265*37da2899SCharles.Forsyth 1266*37da2899SCharles.Forsyth /* all right, this is an opened path, we need to add a cap between */ 1267*37da2899SCharles.Forsyth /* right & left, add the reverse of left, then add a final cap between */ 1268*37da2899SCharles.Forsyth /* left & right.. */ 1269*37da2899SCharles.Forsyth error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); 1270*37da2899SCharles.Forsyth if (error) goto Exit; 1271*37da2899SCharles.Forsyth 1272*37da2899SCharles.Forsyth /* add reversed points from "left" to "right" */ 1273*37da2899SCharles.Forsyth error = ft_stroker_add_reverse_left( stroker, 1 ); 1274*37da2899SCharles.Forsyth if (error) goto Exit; 1275*37da2899SCharles.Forsyth 1276*37da2899SCharles.Forsyth /* now add the final cap */ 1277*37da2899SCharles.Forsyth stroker->center = stroker->subpath_start; 1278*37da2899SCharles.Forsyth error = ft_stroker_cap( stroker, stroker->subpath_angle+FT_ANGLE_PI, 0 ); 1279*37da2899SCharles.Forsyth if (error) goto Exit; 1280*37da2899SCharles.Forsyth 1281*37da2899SCharles.Forsyth /* now, end the right subpath accordingly. the left one is */ 1282*37da2899SCharles.Forsyth /* rewind and doesn't need further processing.. */ 1283*37da2899SCharles.Forsyth ft_stroke_border_close( right ); 1284*37da2899SCharles.Forsyth } 1285*37da2899SCharles.Forsyth else 1286*37da2899SCharles.Forsyth { 1287*37da2899SCharles.Forsyth FT_Angle turn; 1288*37da2899SCharles.Forsyth FT_Int inside_side; 1289*37da2899SCharles.Forsyth 1290*37da2899SCharles.Forsyth /* process the corner ... */ 1291*37da2899SCharles.Forsyth stroker->angle_out = stroker->subpath_angle; 1292*37da2899SCharles.Forsyth turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 1293*37da2899SCharles.Forsyth 1294*37da2899SCharles.Forsyth /* no specific corner processing is required if the turn is 0 */ 1295*37da2899SCharles.Forsyth if (turn != 0) 1296*37da2899SCharles.Forsyth { 1297*37da2899SCharles.Forsyth /* when we turn to the right, the inside side is 0 */ 1298*37da2899SCharles.Forsyth inside_side = 0; 1299*37da2899SCharles.Forsyth 1300*37da2899SCharles.Forsyth /* otherwise, the inside side is 1 */ 1301*37da2899SCharles.Forsyth if (turn < 0) 1302*37da2899SCharles.Forsyth inside_side = 1; 1303*37da2899SCharles.Forsyth 1304*37da2899SCharles.Forsyth /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE !! */ 1305*37da2899SCharles.Forsyth /* process the inside side */ 1306*37da2899SCharles.Forsyth /* error = ft_stroker_inside( stroker, inside_side ); 1307*37da2899SCharles.Forsyth if (error) goto Exit; */ 1308*37da2899SCharles.Forsyth 1309*37da2899SCharles.Forsyth /* process the outside side */ 1310*37da2899SCharles.Forsyth error = ft_stroker_outside( stroker, 1-inside_side ); 1311*37da2899SCharles.Forsyth if (error) goto Exit; 1312*37da2899SCharles.Forsyth } 1313*37da2899SCharles.Forsyth 1314*37da2899SCharles.Forsyth /* we will first end our two subpaths */ 1315*37da2899SCharles.Forsyth ft_stroke_border_close( stroker->borders + 0 ); 1316*37da2899SCharles.Forsyth ft_stroke_border_close( stroker->borders + 1 ); 1317*37da2899SCharles.Forsyth 1318*37da2899SCharles.Forsyth /* now, add the reversed left subpath to "right" */ 1319*37da2899SCharles.Forsyth error = ft_stroker_add_reverse_left( stroker, 0 ); 1320*37da2899SCharles.Forsyth if (error) goto Exit; 1321*37da2899SCharles.Forsyth } 1322*37da2899SCharles.Forsyth 1323*37da2899SCharles.Forsyth Exit: 1324*37da2899SCharles.Forsyth return error; 1325*37da2899SCharles.Forsyth } 1326*37da2899SCharles.Forsyth 1327*37da2899SCharles.Forsyth 1328*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_Stroker_GetCounts(FT_Stroker stroker,FT_UInt * anum_points,FT_UInt * anum_contours)1329*37da2899SCharles.Forsyth FT_Stroker_GetCounts( FT_Stroker stroker, 1330*37da2899SCharles.Forsyth FT_UInt *anum_points, 1331*37da2899SCharles.Forsyth FT_UInt *anum_contours ) 1332*37da2899SCharles.Forsyth { 1333*37da2899SCharles.Forsyth FT_UInt count1, count2, num_points = 0; 1334*37da2899SCharles.Forsyth FT_UInt count3, count4, num_contours = 0; 1335*37da2899SCharles.Forsyth FT_Error error; 1336*37da2899SCharles.Forsyth 1337*37da2899SCharles.Forsyth error = ft_stroke_border_get_counts( stroker->borders+0, &count1, &count2 ); 1338*37da2899SCharles.Forsyth if (error) goto Exit; 1339*37da2899SCharles.Forsyth 1340*37da2899SCharles.Forsyth error = ft_stroke_border_get_counts( stroker->borders+1, &count3, &count4 ); 1341*37da2899SCharles.Forsyth if (error) goto Exit; 1342*37da2899SCharles.Forsyth 1343*37da2899SCharles.Forsyth num_points = count1 + count3; 1344*37da2899SCharles.Forsyth num_contours = count2 + count4; 1345*37da2899SCharles.Forsyth 1346*37da2899SCharles.Forsyth stroker->valid = 1; 1347*37da2899SCharles.Forsyth 1348*37da2899SCharles.Forsyth Exit: 1349*37da2899SCharles.Forsyth *anum_points = num_points; 1350*37da2899SCharles.Forsyth *anum_contours = num_contours; 1351*37da2899SCharles.Forsyth return error; 1352*37da2899SCharles.Forsyth } 1353*37da2899SCharles.Forsyth 1354*37da2899SCharles.Forsyth 1355*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_Stroker_Export(FT_Stroker stroker,FT_Outline * outline)1356*37da2899SCharles.Forsyth FT_Stroker_Export( FT_Stroker stroker, 1357*37da2899SCharles.Forsyth FT_Outline* outline ) 1358*37da2899SCharles.Forsyth { 1359*37da2899SCharles.Forsyth if ( stroker->valid ) 1360*37da2899SCharles.Forsyth { 1361*37da2899SCharles.Forsyth ft_stroke_border_export( stroker->borders+0, outline ); 1362*37da2899SCharles.Forsyth ft_stroke_border_export( stroker->borders+1, outline ); 1363*37da2899SCharles.Forsyth } 1364*37da2899SCharles.Forsyth } 1365