Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftstroke.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ftstroke.c */ 00004 /* */ 00005 /* FreeType path stroker (body). */ 00006 /* */ 00007 /* Copyright 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 00019 #include <ft2build.h> 00020 #include FT_STROKER_H 00021 #include FT_TRIGONOMETRY_H 00022 #include FT_OUTLINE_H 00023 #include FT_INTERNAL_MEMORY_H 00024 #include FT_INTERNAL_DEBUG_H 00025 #include FT_INTERNAL_OBJECTS_H 00026 00027 00028 /* documentation is in ftstroke.h */ 00029 00030 FT_EXPORT_DEF( FT_StrokerBorder ) 00031 FT_Outline_GetInsideBorder( FT_Outline* outline ) 00032 { 00033 FT_Orientation o = FT_Outline_Get_Orientation( outline ); 00034 00035 00036 return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT 00037 : FT_STROKER_BORDER_LEFT ; 00038 } 00039 00040 00041 /* documentation is in ftstroke.h */ 00042 00043 FT_EXPORT_DEF( FT_StrokerBorder ) 00044 FT_Outline_GetOutsideBorder( FT_Outline* outline ) 00045 { 00046 FT_Orientation o = FT_Outline_Get_Orientation( outline ); 00047 00048 00049 return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT 00050 : FT_STROKER_BORDER_RIGHT ; 00051 } 00052 00053 00054 /***************************************************************************/ 00055 /***************************************************************************/ 00056 /***** *****/ 00057 /***** BEZIER COMPUTATIONS *****/ 00058 /***** *****/ 00059 /***************************************************************************/ 00060 /***************************************************************************/ 00061 00062 #define FT_SMALL_CONIC_THRESHOLD ( FT_ANGLE_PI / 6 ) 00063 #define FT_SMALL_CUBIC_THRESHOLD ( FT_ANGLE_PI / 6 ) 00064 #define FT_EPSILON 2 00065 00066 #define FT_IS_SMALL( x ) ( (x) > -FT_EPSILON && (x) < FT_EPSILON ) 00067 00068 00069 static FT_Pos 00070 ft_pos_abs( FT_Pos x ) 00071 { 00072 return x >= 0 ? x : -x ; 00073 } 00074 00075 00076 static void 00077 ft_conic_split( FT_Vector* base ) 00078 { 00079 FT_Pos a, b; 00080 00081 00082 base[4].x = base[2].x; 00083 b = base[1].x; 00084 a = base[3].x = ( base[2].x + b ) / 2; 00085 b = base[1].x = ( base[0].x + b ) / 2; 00086 base[2].x = ( a + b ) / 2; 00087 00088 base[4].y = base[2].y; 00089 b = base[1].y; 00090 a = base[3].y = ( base[2].y + b ) / 2; 00091 b = base[1].y = ( base[0].y + b ) / 2; 00092 base[2].y = ( a + b ) / 2; 00093 } 00094 00095 00096 static FT_Bool 00097 ft_conic_is_small_enough( FT_Vector* base, 00098 FT_Angle *angle_in, 00099 FT_Angle *angle_out ) 00100 { 00101 FT_Vector d1, d2; 00102 FT_Angle theta; 00103 FT_Int close1, close2; 00104 00105 00106 d1.x = base[1].x - base[2].x; 00107 d1.y = base[1].y - base[2].y; 00108 d2.x = base[0].x - base[1].x; 00109 d2.y = base[0].y - base[1].y; 00110 00111 close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); 00112 close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); 00113 00114 if ( close1 ) 00115 { 00116 if ( close2 ) 00117 *angle_in = *angle_out = 0; 00118 else 00119 *angle_in = *angle_out = FT_Atan2( d2.x, d2.y ); 00120 } 00121 else if ( close2 ) 00122 { 00123 *angle_in = *angle_out = FT_Atan2( d1.x, d1.y ); 00124 } 00125 else 00126 { 00127 *angle_in = FT_Atan2( d1.x, d1.y ); 00128 *angle_out = FT_Atan2( d2.x, d2.y ); 00129 } 00130 00131 theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) ); 00132 00133 return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD ); 00134 } 00135 00136 00137 static void 00138 ft_cubic_split( FT_Vector* base ) 00139 { 00140 FT_Pos a, b, c, d; 00141 00142 00143 base[6].x = base[3].x; 00144 c = base[1].x; 00145 d = base[2].x; 00146 base[1].x = a = ( base[0].x + c ) / 2; 00147 base[5].x = b = ( base[3].x + d ) / 2; 00148 c = ( c + d ) / 2; 00149 base[2].x = a = ( a + c ) / 2; 00150 base[4].x = b = ( b + c ) / 2; 00151 base[3].x = ( a + b ) / 2; 00152 00153 base[6].y = base[3].y; 00154 c = base[1].y; 00155 d = base[2].y; 00156 base[1].y = a = ( base[0].y + c ) / 2; 00157 base[5].y = b = ( base[3].y + d ) / 2; 00158 c = ( c + d ) / 2; 00159 base[2].y = a = ( a + c ) / 2; 00160 base[4].y = b = ( b + c ) / 2; 00161 base[3].y = ( a + b ) / 2; 00162 } 00163 00164 00165 static FT_Bool 00166 ft_cubic_is_small_enough( FT_Vector* base, 00167 FT_Angle *angle_in, 00168 FT_Angle *angle_mid, 00169 FT_Angle *angle_out ) 00170 { 00171 FT_Vector d1, d2, d3; 00172 FT_Angle theta1, theta2; 00173 FT_Int close1, close2, close3; 00174 00175 00176 d1.x = base[2].x - base[3].x; 00177 d1.y = base[2].y - base[3].y; 00178 d2.x = base[1].x - base[2].x; 00179 d2.y = base[1].y - base[2].y; 00180 d3.x = base[0].x - base[1].x; 00181 d3.y = base[0].y - base[1].y; 00182 00183 close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y ); 00184 close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y ); 00185 close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y ); 00186 00187 if ( close1 || close3 ) 00188 { 00189 if ( close2 ) 00190 { 00191 /* basically a point */ 00192 *angle_in = *angle_out = *angle_mid = 0; 00193 } 00194 else if ( close1 ) 00195 { 00196 *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y ); 00197 *angle_out = FT_Atan2( d3.x, d3.y ); 00198 } 00199 else /* close2 */ 00200 { 00201 *angle_in = FT_Atan2( d1.x, d1.y ); 00202 *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y ); 00203 } 00204 } 00205 else if ( close2 ) 00206 { 00207 *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y ); 00208 *angle_out = FT_Atan2( d3.x, d3.y ); 00209 } 00210 else 00211 { 00212 *angle_in = FT_Atan2( d1.x, d1.y ); 00213 *angle_mid = FT_Atan2( d2.x, d2.y ); 00214 *angle_out = FT_Atan2( d3.x, d3.y ); 00215 } 00216 00217 theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) ); 00218 theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) ); 00219 00220 return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD && 00221 theta2 < FT_SMALL_CUBIC_THRESHOLD ); 00222 } 00223 00224 00225 /***************************************************************************/ 00226 /***************************************************************************/ 00227 /***** *****/ 00228 /***** STROKE BORDERS *****/ 00229 /***** *****/ 00230 /***************************************************************************/ 00231 /***************************************************************************/ 00232 00233 typedef enum FT_StrokeTags_ 00234 { 00235 FT_STROKE_TAG_ON = 1, /* on-curve point */ 00236 FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */ 00237 FT_STROKE_TAG_BEGIN = 4, /* sub-path start */ 00238 FT_STROKE_TAG_END = 8 /* sub-path end */ 00239 00240 } FT_StrokeTags; 00241 00242 #define FT_STROKE_TAG_BEGIN_END (FT_STROKE_TAG_BEGIN|FT_STROKE_TAG_END) 00243 00244 typedef struct FT_StrokeBorderRec_ 00245 { 00246 FT_UInt num_points; 00247 FT_UInt max_points; 00248 FT_Vector* points; 00249 FT_Byte* tags; 00250 FT_Bool movable; 00251 FT_Int start; /* index of current sub-path start point */ 00252 FT_Memory memory; 00253 FT_Bool valid; 00254 00255 } FT_StrokeBorderRec, *FT_StrokeBorder; 00256 00257 00258 static FT_Error 00259 ft_stroke_border_grow( FT_StrokeBorder border, 00260 FT_UInt new_points ) 00261 { 00262 FT_UInt old_max = border->max_points; 00263 FT_UInt new_max = border->num_points + new_points; 00264 FT_Error error = FT_Err_Ok; 00265 00266 00267 if ( new_max > old_max ) 00268 { 00269 FT_UInt cur_max = old_max; 00270 FT_Memory memory = border->memory; 00271 00272 00273 while ( cur_max < new_max ) 00274 cur_max += ( cur_max >> 1 ) + 16; 00275 00276 if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) || 00277 FT_RENEW_ARRAY( border->tags, old_max, cur_max ) ) 00278 goto Exit; 00279 00280 border->max_points = cur_max; 00281 } 00282 00283 Exit: 00284 return error; 00285 } 00286 00287 00288 static void 00289 ft_stroke_border_close( FT_StrokeBorder border, 00290 FT_Bool reverse ) 00291 { 00292 FT_UInt start = border->start; 00293 FT_UInt count = border->num_points; 00294 00295 00296 FT_ASSERT( border->start >= 0 ); 00297 00298 /* don't record empty paths! */ 00299 if ( count <= start + 1U ) 00300 border->num_points = start; 00301 else 00302 { 00303 /* copy the last point to the start of this sub-path, since */ 00304 /* it contains the `adjusted' starting coordinates */ 00305 border->num_points = --count; 00306 border->points[start] = border->points[count]; 00307 00308 if ( reverse ) 00309 { 00310 /* reverse the points */ 00311 { 00312 FT_Vector* vec1 = border->points + start + 1; 00313 FT_Vector* vec2 = border->points + count - 1; 00314 00315 00316 for ( ; vec1 < vec2; vec1++, vec2-- ) 00317 { 00318 FT_Vector tmp; 00319 00320 00321 tmp = *vec1; 00322 *vec1 = *vec2; 00323 *vec2 = tmp; 00324 } 00325 } 00326 00327 /* then the tags */ 00328 { 00329 FT_Byte* tag1 = border->tags + start + 1; 00330 FT_Byte* tag2 = border->tags + count - 1; 00331 00332 00333 for ( ; tag1 < tag2; tag1++, tag2-- ) 00334 { 00335 FT_Byte tmp; 00336 00337 00338 tmp = *tag1; 00339 *tag1 = *tag2; 00340 *tag2 = tmp; 00341 } 00342 } 00343 } 00344 00345 border->tags[start ] |= FT_STROKE_TAG_BEGIN; 00346 border->tags[count - 1] |= FT_STROKE_TAG_END; 00347 } 00348 00349 border->start = -1; 00350 border->movable = FALSE; 00351 } 00352 00353 00354 static FT_Error 00355 ft_stroke_border_lineto( FT_StrokeBorder border, 00356 FT_Vector* to, 00357 FT_Bool movable ) 00358 { 00359 FT_Error error = FT_Err_Ok; 00360 00361 00362 FT_ASSERT( border->start >= 0 ); 00363 00364 if ( border->movable ) 00365 { 00366 /* move last point */ 00367 border->points[border->num_points - 1] = *to; 00368 } 00369 else 00370 { 00371 /* add one point */ 00372 error = ft_stroke_border_grow( border, 1 ); 00373 if ( !error ) 00374 { 00375 FT_Vector* vec = border->points + border->num_points; 00376 FT_Byte* tag = border->tags + border->num_points; 00377 00378 00379 vec[0] = *to; 00380 tag[0] = FT_STROKE_TAG_ON; 00381 00382 border->num_points += 1; 00383 } 00384 } 00385 border->movable = movable; 00386 return error; 00387 } 00388 00389 00390 static FT_Error 00391 ft_stroke_border_conicto( FT_StrokeBorder border, 00392 FT_Vector* control, 00393 FT_Vector* to ) 00394 { 00395 FT_Error error; 00396 00397 00398 FT_ASSERT( border->start >= 0 ); 00399 00400 error = ft_stroke_border_grow( border, 2 ); 00401 if ( !error ) 00402 { 00403 FT_Vector* vec = border->points + border->num_points; 00404 FT_Byte* tag = border->tags + border->num_points; 00405 00406 vec[0] = *control; 00407 vec[1] = *to; 00408 00409 tag[0] = 0; 00410 tag[1] = FT_STROKE_TAG_ON; 00411 00412 border->num_points += 2; 00413 } 00414 border->movable = FALSE; 00415 return error; 00416 } 00417 00418 00419 static FT_Error 00420 ft_stroke_border_cubicto( FT_StrokeBorder border, 00421 FT_Vector* control1, 00422 FT_Vector* control2, 00423 FT_Vector* to ) 00424 { 00425 FT_Error error; 00426 00427 00428 FT_ASSERT( border->start >= 0 ); 00429 00430 error = ft_stroke_border_grow( border, 3 ); 00431 if ( !error ) 00432 { 00433 FT_Vector* vec = border->points + border->num_points; 00434 FT_Byte* tag = border->tags + border->num_points; 00435 00436 00437 vec[0] = *control1; 00438 vec[1] = *control2; 00439 vec[2] = *to; 00440 00441 tag[0] = FT_STROKE_TAG_CUBIC; 00442 tag[1] = FT_STROKE_TAG_CUBIC; 00443 tag[2] = FT_STROKE_TAG_ON; 00444 00445 border->num_points += 3; 00446 } 00447 border->movable = FALSE; 00448 return error; 00449 } 00450 00451 00452 #define FT_ARC_CUBIC_ANGLE ( FT_ANGLE_PI / 2 ) 00453 00454 00455 static FT_Error 00456 ft_stroke_border_arcto( FT_StrokeBorder border, 00457 FT_Vector* center, 00458 FT_Fixed radius, 00459 FT_Angle angle_start, 00460 FT_Angle angle_diff ) 00461 { 00462 FT_Angle total, angle, step, rotate, next, theta; 00463 FT_Vector a, b, a2, b2; 00464 FT_Fixed length; 00465 FT_Error error = FT_Err_Ok; 00466 00467 00468 /* compute start point */ 00469 FT_Vector_From_Polar( &a, radius, angle_start ); 00470 a.x += center->x; 00471 a.y += center->y; 00472 00473 total = angle_diff; 00474 angle = angle_start; 00475 rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2; 00476 00477 while ( total != 0 ) 00478 { 00479 step = total; 00480 if ( step > FT_ARC_CUBIC_ANGLE ) 00481 step = FT_ARC_CUBIC_ANGLE; 00482 00483 else if ( step < -FT_ARC_CUBIC_ANGLE ) 00484 step = -FT_ARC_CUBIC_ANGLE; 00485 00486 next = angle + step; 00487 theta = step; 00488 if ( theta < 0 ) 00489 theta = -theta; 00490 00491 theta >>= 1; 00492 00493 /* compute end point */ 00494 FT_Vector_From_Polar( &b, radius, next ); 00495 b.x += center->x; 00496 b.y += center->y; 00497 00498 /* compute first and second control points */ 00499 length = FT_MulDiv( radius, FT_Sin( theta ) * 4, 00500 ( 0x10000L + FT_Cos( theta ) ) * 3 ); 00501 00502 FT_Vector_From_Polar( &a2, length, angle + rotate ); 00503 a2.x += a.x; 00504 a2.y += a.y; 00505 00506 FT_Vector_From_Polar( &b2, length, next - rotate ); 00507 b2.x += b.x; 00508 b2.y += b.y; 00509 00510 /* add cubic arc */ 00511 error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); 00512 if ( error ) 00513 break; 00514 00515 /* process the rest of the arc ?? */ 00516 a = b; 00517 total -= step; 00518 angle = next; 00519 } 00520 00521 return error; 00522 } 00523 00524 00525 static FT_Error 00526 ft_stroke_border_moveto( FT_StrokeBorder border, 00527 FT_Vector* to ) 00528 { 00529 /* close current open path if any ? */ 00530 if ( border->start >= 0 ) 00531 ft_stroke_border_close( border, FALSE ); 00532 00533 border->start = border->num_points; 00534 border->movable = FALSE; 00535 00536 return ft_stroke_border_lineto( border, to, FALSE ); 00537 } 00538 00539 00540 static void 00541 ft_stroke_border_init( FT_StrokeBorder border, 00542 FT_Memory memory ) 00543 { 00544 border->memory = memory; 00545 border->points = NULL; 00546 border->tags = NULL; 00547 00548 border->num_points = 0; 00549 border->max_points = 0; 00550 border->start = -1; 00551 border->valid = FALSE; 00552 } 00553 00554 00555 static void 00556 ft_stroke_border_reset( FT_StrokeBorder border ) 00557 { 00558 border->num_points = 0; 00559 border->start = -1; 00560 border->valid = FALSE; 00561 } 00562 00563 00564 static void 00565 ft_stroke_border_done( FT_StrokeBorder border ) 00566 { 00567 FT_Memory memory = border->memory; 00568 00569 00570 FT_FREE( border->points ); 00571 FT_FREE( border->tags ); 00572 00573 border->num_points = 0; 00574 border->max_points = 0; 00575 border->start = -1; 00576 border->valid = FALSE; 00577 } 00578 00579 00580 static FT_Error 00581 ft_stroke_border_get_counts( FT_StrokeBorder border, 00582 FT_UInt *anum_points, 00583 FT_UInt *anum_contours ) 00584 { 00585 FT_Error error = FT_Err_Ok; 00586 FT_UInt num_points = 0; 00587 FT_UInt num_contours = 0; 00588 00589 FT_UInt count = border->num_points; 00590 FT_Vector* point = border->points; 00591 FT_Byte* tags = border->tags; 00592 FT_Int in_contour = 0; 00593 00594 00595 for ( ; count > 0; count--, num_points++, point++, tags++ ) 00596 { 00597 if ( tags[0] & FT_STROKE_TAG_BEGIN ) 00598 { 00599 if ( in_contour != 0 ) 00600 goto Fail; 00601 00602 in_contour = 1; 00603 } 00604 else if ( in_contour == 0 ) 00605 goto Fail; 00606 00607 if ( tags[0] & FT_STROKE_TAG_END ) 00608 { 00609 in_contour = 0; 00610 num_contours++; 00611 } 00612 } 00613 00614 if ( in_contour != 0 ) 00615 goto Fail; 00616 00617 border->valid = TRUE; 00618 00619 Exit: 00620 *anum_points = num_points; 00621 *anum_contours = num_contours; 00622 return error; 00623 00624 Fail: 00625 num_points = 0; 00626 num_contours = 0; 00627 goto Exit; 00628 } 00629 00630 00631 static void 00632 ft_stroke_border_export( FT_StrokeBorder border, 00633 FT_Outline* outline ) 00634 { 00635 /* copy point locations */ 00636 FT_ARRAY_COPY( outline->points + outline->n_points, 00637 border->points, 00638 border->num_points ); 00639 00640 /* copy tags */ 00641 { 00642 FT_UInt count = border->num_points; 00643 FT_Byte* read = border->tags; 00644 FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; 00645 00646 00647 for ( ; count > 0; count--, read++, write++ ) 00648 { 00649 if ( *read & FT_STROKE_TAG_ON ) 00650 *write = FT_CURVE_TAG_ON; 00651 else if ( *read & FT_STROKE_TAG_CUBIC ) 00652 *write = FT_CURVE_TAG_CUBIC; 00653 else 00654 *write = FT_CURVE_TAG_CONIC; 00655 } 00656 } 00657 00658 /* copy contours */ 00659 { 00660 FT_UInt count = border->num_points; 00661 FT_Byte* tags = border->tags; 00662 FT_Short* write = outline->contours + outline->n_contours; 00663 FT_Short idx = (FT_Short)outline->n_points; 00664 00665 00666 for ( ; count > 0; count--, tags++, idx++ ) 00667 { 00668 if ( *tags & FT_STROKE_TAG_END ) 00669 { 00670 *write++ = idx; 00671 outline->n_contours++; 00672 } 00673 } 00674 } 00675 00676 outline->n_points = (short)( outline->n_points + border->num_points ); 00677 00678 FT_ASSERT( FT_Outline_Check( outline ) == 0 ); 00679 } 00680 00681 00682 /***************************************************************************/ 00683 /***************************************************************************/ 00684 /***** *****/ 00685 /***** STROKER *****/ 00686 /***** *****/ 00687 /***************************************************************************/ 00688 /***************************************************************************/ 00689 00690 #define FT_SIDE_TO_ROTATE( s ) ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI ) 00691 00692 typedef struct FT_StrokerRec_ 00693 { 00694 FT_Angle angle_in; 00695 FT_Angle angle_out; 00696 FT_Vector center; 00697 FT_Bool first_point; 00698 FT_Bool subpath_open; 00699 FT_Angle subpath_angle; 00700 FT_Vector subpath_start; 00701 00702 FT_Stroker_LineCap line_cap; 00703 FT_Stroker_LineJoin line_join; 00704 FT_Fixed miter_limit; 00705 FT_Fixed radius; 00706 00707 FT_Bool valid; 00708 FT_StrokeBorderRec borders[2]; 00709 FT_Library library; 00710 00711 } FT_StrokerRec; 00712 00713 00714 /* documentation is in ftstroke.h */ 00715 00716 FT_EXPORT_DEF( FT_Error ) 00717 FT_Stroker_New( FT_Library library, 00718 FT_Stroker *astroker ) 00719 { 00720 FT_Error error; 00721 FT_Memory memory; 00722 FT_Stroker stroker; 00723 00724 00725 if ( !library ) 00726 return FT_Err_Invalid_Argument; 00727 00728 memory = library->memory; 00729 00730 if ( !FT_NEW( stroker ) ) 00731 { 00732 stroker->library = library; 00733 00734 ft_stroke_border_init( &stroker->borders[0], memory ); 00735 ft_stroke_border_init( &stroker->borders[1], memory ); 00736 } 00737 *astroker = stroker; 00738 return error; 00739 } 00740 00741 00742 /* documentation is in ftstroke.h */ 00743 00744 FT_EXPORT_DEF( void ) 00745 FT_Stroker_Set( FT_Stroker stroker, 00746 FT_Fixed radius, 00747 FT_Stroker_LineCap line_cap, 00748 FT_Stroker_LineJoin line_join, 00749 FT_Fixed miter_limit ) 00750 { 00751 stroker->radius = radius; 00752 stroker->line_cap = line_cap; 00753 stroker->line_join = line_join; 00754 stroker->miter_limit = miter_limit; 00755 00756 FT_Stroker_Rewind( stroker ); 00757 } 00758 00759 00760 /* documentation is in ftstroke.h */ 00761 00762 FT_EXPORT_DEF( void ) 00763 FT_Stroker_Rewind( FT_Stroker stroker ) 00764 { 00765 if ( stroker ) 00766 { 00767 ft_stroke_border_reset( &stroker->borders[0] ); 00768 ft_stroke_border_reset( &stroker->borders[1] ); 00769 } 00770 } 00771 00772 00773 /* documentation is in ftstroke.h */ 00774 00775 FT_EXPORT_DEF( void ) 00776 FT_Stroker_Done( FT_Stroker stroker ) 00777 { 00778 if ( stroker ) 00779 { 00780 FT_Memory memory = stroker->library->memory; 00781 00782 00783 ft_stroke_border_done( &stroker->borders[0] ); 00784 ft_stroke_border_done( &stroker->borders[1] ); 00785 00786 stroker->library = NULL; 00787 FT_FREE( stroker ); 00788 } 00789 } 00790 00791 00792 /* creates a circular arc at a corner or cap */ 00793 static FT_Error 00794 ft_stroker_arcto( FT_Stroker stroker, 00795 FT_Int side ) 00796 { 00797 FT_Angle total, rotate; 00798 FT_Fixed radius = stroker->radius; 00799 FT_Error error = FT_Err_Ok; 00800 FT_StrokeBorder border = stroker->borders + side; 00801 00802 00803 rotate = FT_SIDE_TO_ROTATE( side ); 00804 00805 total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 00806 if ( total == FT_ANGLE_PI ) 00807 total = -rotate * 2; 00808 00809 error = ft_stroke_border_arcto( border, 00810 &stroker->center, 00811 radius, 00812 stroker->angle_in + rotate, 00813 total ); 00814 border->movable = FALSE; 00815 return error; 00816 } 00817 00818 00819 /* adds a cap at the end of an opened path */ 00820 static FT_Error 00821 ft_stroker_cap( FT_Stroker stroker, 00822 FT_Angle angle, 00823 FT_Int side ) 00824 { 00825 FT_Error error = FT_Err_Ok; 00826 00827 00828 if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND ) 00829 { 00830 /* add a round cap */ 00831 stroker->angle_in = angle; 00832 stroker->angle_out = angle + FT_ANGLE_PI; 00833 error = ft_stroker_arcto( stroker, side ); 00834 } 00835 else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) 00836 { 00837 /* add a square cap */ 00838 FT_Vector delta, delta2; 00839 FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); 00840 FT_Fixed radius = stroker->radius; 00841 FT_StrokeBorder border = stroker->borders + side; 00842 00843 00844 FT_Vector_From_Polar( &delta2, radius, angle + rotate ); 00845 FT_Vector_From_Polar( &delta, radius, angle ); 00846 00847 delta.x += stroker->center.x + delta2.x; 00848 delta.y += stroker->center.y + delta2.y; 00849 00850 error = ft_stroke_border_lineto( border, &delta, FALSE ); 00851 if ( error ) 00852 goto Exit; 00853 00854 FT_Vector_From_Polar( &delta2, radius, angle - rotate ); 00855 FT_Vector_From_Polar( &delta, radius, angle ); 00856 00857 delta.x += delta2.x + stroker->center.x; 00858 delta.y += delta2.y + stroker->center.y; 00859 00860 error = ft_stroke_border_lineto( border, &delta, FALSE ); 00861 } 00862 else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT ) 00863 { 00864 /* add a butt ending */ 00865 FT_Vector delta; 00866 FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); 00867 FT_Fixed radius = stroker->radius; 00868 FT_StrokeBorder border = stroker->borders + side; 00869 00870 00871 FT_Vector_From_Polar( &delta, radius, angle + rotate ); 00872 00873 delta.x += stroker->center.x; 00874 delta.y += stroker->center.y; 00875 00876 error = ft_stroke_border_lineto( border, &delta, FALSE ); 00877 if ( error ) 00878 goto Exit; 00879 00880 FT_Vector_From_Polar( &delta, radius, angle - rotate ); 00881 00882 delta.x += stroker->center.x; 00883 delta.y += stroker->center.y; 00884 00885 error = ft_stroke_border_lineto( border, &delta, FALSE ); 00886 } 00887 00888 Exit: 00889 return error; 00890 } 00891 00892 00893 /* process an inside corner, i.e. compute intersection */ 00894 static FT_Error 00895 ft_stroker_inside( FT_Stroker stroker, 00896 FT_Int side) 00897 { 00898 FT_StrokeBorder border = stroker->borders + side; 00899 FT_Angle phi, theta, rotate; 00900 FT_Fixed length, thcos, sigma; 00901 FT_Vector delta; 00902 FT_Error error = FT_Err_Ok; 00903 00904 00905 rotate = FT_SIDE_TO_ROTATE( side ); 00906 00907 /* compute median angle */ 00908 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 00909 if ( theta == FT_ANGLE_PI ) 00910 theta = rotate; 00911 else 00912 theta = theta / 2; 00913 00914 phi = stroker->angle_in + theta; 00915 00916 thcos = FT_Cos( theta ); 00917 sigma = FT_MulFix( stroker->miter_limit, thcos ); 00918 00919 /* TODO: find better criterion to switch off the optimization */ 00920 if ( sigma < 0x10000L ) 00921 { 00922 FT_Vector_From_Polar( &delta, stroker->radius, 00923 stroker->angle_out + rotate ); 00924 delta.x += stroker->center.x; 00925 delta.y += stroker->center.y; 00926 border->movable = FALSE; 00927 } 00928 else 00929 { 00930 length = FT_DivFix( stroker->radius, thcos ); 00931 00932 FT_Vector_From_Polar( &delta, length, phi + rotate ); 00933 delta.x += stroker->center.x; 00934 delta.y += stroker->center.y; 00935 } 00936 00937 error = ft_stroke_border_lineto( border, &delta, FALSE ); 00938 00939 return error; 00940 } 00941 00942 00943 /* process an outside corner, i.e. compute bevel/miter/round */ 00944 static FT_Error 00945 ft_stroker_outside( FT_Stroker stroker, 00946 FT_Int side ) 00947 { 00948 FT_StrokeBorder border = stroker->borders + side; 00949 FT_Error error; 00950 FT_Angle rotate; 00951 00952 00953 if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND ) 00954 error = ft_stroker_arcto( stroker, side ); 00955 else 00956 { 00957 /* this is a mitered or beveled corner */ 00958 FT_Fixed sigma, radius = stroker->radius; 00959 FT_Angle theta, phi; 00960 FT_Fixed thcos; 00961 FT_Bool miter; 00962 00963 00964 rotate = FT_SIDE_TO_ROTATE( side ); 00965 miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER ); 00966 00967 theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 00968 if ( theta == FT_ANGLE_PI ) 00969 { 00970 theta = rotate; 00971 phi = stroker->angle_in; 00972 } 00973 else 00974 { 00975 theta = theta / 2; 00976 phi = stroker->angle_in + theta + rotate; 00977 } 00978 00979 thcos = FT_Cos( theta ); 00980 sigma = FT_MulFix( stroker->miter_limit, thcos ); 00981 00982 /* FT_Sin(x) = 0 for x <= 57 */ 00983 if ( sigma >= 0x10000L || ft_pos_abs( theta ) <= 57 ) 00984 miter = FALSE; 00985 00986 if ( miter ) /* this is a miter (broken angle) */ 00987 { 00988 FT_Vector middle, delta; 00989 FT_Fixed length; 00990 00991 00992 /* compute middle point */ 00993 FT_Vector_From_Polar( &middle, 00994 FT_MulFix( radius, stroker->miter_limit ), 00995 phi ); 00996 middle.x += stroker->center.x; 00997 middle.y += stroker->center.y; 00998 00999 /* compute first angle point */ 01000 length = FT_MulFix( radius, 01001 FT_DivFix( 0x10000L - sigma, 01002 ft_pos_abs( FT_Sin( theta ) ) ) ); 01003 01004 FT_Vector_From_Polar( &delta, length, phi + rotate ); 01005 delta.x += middle.x; 01006 delta.y += middle.y; 01007 01008 error = ft_stroke_border_lineto( border, &delta, FALSE ); 01009 if ( error ) 01010 goto Exit; 01011 01012 /* compute second angle point */ 01013 FT_Vector_From_Polar( &delta, length, phi - rotate ); 01014 delta.x += middle.x; 01015 delta.y += middle.y; 01016 01017 error = ft_stroke_border_lineto( border, &delta, FALSE ); 01018 if ( error ) 01019 goto Exit; 01020 01021 /* finally, add a movable end point */ 01022 FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate ); 01023 delta.x += stroker->center.x; 01024 delta.y += stroker->center.y; 01025 01026 error = ft_stroke_border_lineto( border, &delta, TRUE ); 01027 } 01028 01029 else /* this is a bevel (intersection) */ 01030 { 01031 FT_Fixed length; 01032 FT_Vector delta; 01033 01034 01035 length = FT_DivFix( stroker->radius, thcos ); 01036 01037 FT_Vector_From_Polar( &delta, length, phi ); 01038 delta.x += stroker->center.x; 01039 delta.y += stroker->center.y; 01040 01041 error = ft_stroke_border_lineto( border, &delta, FALSE ); 01042 if ( error ) 01043 goto Exit; 01044 01045 /* now add end point */ 01046 FT_Vector_From_Polar( &delta, stroker->radius, 01047 stroker->angle_out + rotate ); 01048 delta.x += stroker->center.x; 01049 delta.y += stroker->center.y; 01050 01051 error = ft_stroke_border_lineto( border, &delta, TRUE ); 01052 } 01053 } 01054 01055 Exit: 01056 return error; 01057 } 01058 01059 01060 static FT_Error 01061 ft_stroker_process_corner( FT_Stroker stroker ) 01062 { 01063 FT_Error error = FT_Err_Ok; 01064 FT_Angle turn; 01065 FT_Int inside_side; 01066 01067 01068 turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); 01069 01070 /* no specific corner processing is required if the turn is 0 */ 01071 if ( turn == 0 ) 01072 goto Exit; 01073 01074 /* when we turn to the right, the inside side is 0 */ 01075 inside_side = 0; 01076 01077 /* otherwise, the inside side is 1 */ 01078 if ( turn < 0 ) 01079 inside_side = 1; 01080 01081 /* process the inside side */ 01082 error = ft_stroker_inside( stroker, inside_side ); 01083 if ( error ) 01084 goto Exit; 01085 01086 /* process the outside side */ 01087 error = ft_stroker_outside( stroker, 1 - inside_side ); 01088 01089 Exit: 01090 return error; 01091 } 01092 01093 01094 /* add two points to the left and right borders corresponding to the */ 01095 /* start of the subpath */ 01096 static FT_Error 01097 ft_stroker_subpath_start( FT_Stroker stroker, 01098 FT_Angle start_angle ) 01099 { 01100 FT_Vector delta; 01101 FT_Vector point; 01102 FT_Error error; 01103 FT_StrokeBorder border; 01104 01105 01106 FT_Vector_From_Polar( &delta, stroker->radius, 01107 start_angle + FT_ANGLE_PI2 ); 01108 01109 point.x = stroker->center.x + delta.x; 01110 point.y = stroker->center.y + delta.y; 01111 01112 border = stroker->borders; 01113 error = ft_stroke_border_moveto( border, &point ); 01114 if ( error ) 01115 goto Exit; 01116 01117 point.x = stroker->center.x - delta.x; 01118 point.y = stroker->center.y - delta.y; 01119 01120 border++; 01121 error = ft_stroke_border_moveto( border, &point ); 01122 01123 /* save angle for last cap */ 01124 stroker->subpath_angle = start_angle; 01125 stroker->first_point = FALSE; 01126 01127 Exit: 01128 return error; 01129 } 01130 01131 01132 /* documentation is in ftstroke.h */ 01133 01134 FT_EXPORT_DEF( FT_Error ) 01135 FT_Stroker_LineTo( FT_Stroker stroker, 01136 FT_Vector* to ) 01137 { 01138 FT_Error error = FT_Err_Ok; 01139 FT_StrokeBorder border; 01140 FT_Vector delta; 01141 FT_Angle angle; 01142 FT_Int side; 01143 01144 delta.x = to->x - stroker->center.x; 01145 delta.y = to->y - stroker->center.y; 01146 01147 angle = FT_Atan2( delta.x, delta.y ); 01148 FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 ); 01149 01150 /* process corner if necessary */ 01151 if ( stroker->first_point ) 01152 { 01153 /* This is the first segment of a subpath. We need to */ 01154 /* add a point to each border at their respective starting */ 01155 /* point locations. */ 01156 error = ft_stroker_subpath_start( stroker, angle ); 01157 if ( error ) 01158 goto Exit; 01159 } 01160 else 01161 { 01162 /* process the current corner */ 01163 stroker->angle_out = angle; 01164 error = ft_stroker_process_corner( stroker ); 01165 if ( error ) 01166 goto Exit; 01167 } 01168 01169 /* now add a line segment to both the `inside' and `outside' paths */ 01170 01171 for ( border = stroker->borders, side = 1; side >= 0; side--, border++ ) 01172 { 01173 FT_Vector point; 01174 01175 01176 point.x = to->x + delta.x; 01177 point.y = to->y + delta.y; 01178 01179 error = ft_stroke_border_lineto( border, &point, TRUE ); 01180 if ( error ) 01181 goto Exit; 01182 01183 delta.x = -delta.x; 01184 delta.y = -delta.y; 01185 } 01186 01187 stroker->angle_in = angle; 01188 stroker->center = *to; 01189 01190 Exit: 01191 return error; 01192 } 01193 01194 01195 /* documentation is in ftstroke.h */ 01196 01197 FT_EXPORT_DEF( FT_Error ) 01198 FT_Stroker_ConicTo( FT_Stroker stroker, 01199 FT_Vector* control, 01200 FT_Vector* to ) 01201 { 01202 FT_Error error = FT_Err_Ok; 01203 FT_Vector bez_stack[34]; 01204 FT_Vector* arc; 01205 FT_Vector* limit = bez_stack + 30; 01206 FT_Angle start_angle; 01207 FT_Bool first_arc = TRUE; 01208 01209 01210 arc = bez_stack; 01211 arc[0] = *to; 01212 arc[1] = *control; 01213 arc[2] = stroker->center; 01214 01215 while ( arc >= bez_stack ) 01216 { 01217 FT_Angle angle_in, angle_out; 01218 01219 01220 angle_in = angle_out = 0; /* remove compiler warnings */ 01221 01222 if ( arc < limit && 01223 !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) ) 01224 { 01225 ft_conic_split( arc ); 01226 arc += 2; 01227 continue; 01228 } 01229 01230 if ( first_arc ) 01231 { 01232 first_arc = FALSE; 01233 01234 start_angle = angle_in; 01235 01236 /* process corner if necessary */ 01237 if ( stroker->first_point ) 01238 error = ft_stroker_subpath_start( stroker, start_angle ); 01239 else 01240 { 01241 stroker->angle_out = start_angle; 01242 error = ft_stroker_process_corner( stroker ); 01243 } 01244 } 01245 01246 /* the arc's angle is small enough; we can add it directly to each */ 01247 /* border */ 01248 { 01249 FT_Vector ctrl, end; 01250 FT_Angle theta, phi, rotate; 01251 FT_Fixed length; 01252 FT_Int side; 01253 01254 01255 theta = FT_Angle_Diff( angle_in, angle_out ) / 2; 01256 phi = angle_in + theta; 01257 length = FT_DivFix( stroker->radius, FT_Cos( theta ) ); 01258 01259 for ( side = 0; side <= 1; side++ ) 01260 { 01261 rotate = FT_SIDE_TO_ROTATE( side ); 01262 01263 /* compute control point */ 01264 FT_Vector_From_Polar( &ctrl, length, phi + rotate ); 01265 ctrl.x += arc[1].x; 01266 ctrl.y += arc[1].y; 01267 01268 /* compute end point */ 01269 FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); 01270 end.x += arc[0].x; 01271 end.y += arc[0].y; 01272 01273 error = ft_stroke_border_conicto( stroker->borders + side, 01274 &ctrl, &end ); 01275 if ( error ) 01276 goto Exit; 01277 } 01278 } 01279 01280 arc -= 2; 01281 01282 if ( arc < bez_stack ) 01283 stroker->angle_in = angle_out; 01284 } 01285 01286 stroker->center = *to; 01287 01288 Exit: 01289 return error; 01290 } 01291 01292 01293 /* documentation is in ftstroke.h */ 01294 01295 FT_EXPORT_DEF( FT_Error ) 01296 FT_Stroker_CubicTo( FT_Stroker stroker, 01297 FT_Vector* control1, 01298 FT_Vector* control2, 01299 FT_Vector* to ) 01300 { 01301 FT_Error error = FT_Err_Ok; 01302 FT_Vector bez_stack[37]; 01303 FT_Vector* arc; 01304 FT_Vector* limit = bez_stack + 32; 01305 FT_Angle start_angle; 01306 FT_Bool first_arc = TRUE; 01307 01308 01309 arc = bez_stack; 01310 arc[0] = *to; 01311 arc[1] = *control2; 01312 arc[2] = *control1; 01313 arc[3] = stroker->center; 01314 01315 while ( arc >= bez_stack ) 01316 { 01317 FT_Angle angle_in, angle_mid, angle_out; 01318 01319 01320 /* remove compiler warnings */ 01321 angle_in = angle_out = angle_mid = 0; 01322 01323 if ( arc < limit && 01324 !ft_cubic_is_small_enough( arc, &angle_in, 01325 &angle_mid, &angle_out ) ) 01326 { 01327 ft_cubic_split( arc ); 01328 arc += 3; 01329 continue; 01330 } 01331 01332 if ( first_arc ) 01333 { 01334 first_arc = FALSE; 01335 01336 /* process corner if necessary */ 01337 start_angle = angle_in; 01338 01339 if ( stroker->first_point ) 01340 error = ft_stroker_subpath_start( stroker, start_angle ); 01341 else 01342 { 01343 stroker->angle_out = start_angle; 01344 error = ft_stroker_process_corner( stroker ); 01345 } 01346 if ( error ) 01347 goto Exit; 01348 } 01349 01350 /* the arc's angle is small enough; we can add it directly to each */ 01351 /* border */ 01352 { 01353 FT_Vector ctrl1, ctrl2, end; 01354 FT_Angle theta1, phi1, theta2, phi2, rotate; 01355 FT_Fixed length1, length2; 01356 FT_Int side; 01357 01358 01359 theta1 = ft_pos_abs( angle_mid - angle_in ) / 2; 01360 theta2 = ft_pos_abs( angle_out - angle_mid ) / 2; 01361 phi1 = (angle_mid + angle_in ) / 2; 01362 phi2 = (angle_mid + angle_out ) / 2; 01363 length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) ); 01364 length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) ); 01365 01366 for ( side = 0; side <= 1; side++ ) 01367 { 01368 rotate = FT_SIDE_TO_ROTATE( side ); 01369 01370 /* compute control points */ 01371 FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate ); 01372 ctrl1.x += arc[2].x; 01373 ctrl1.y += arc[2].y; 01374 01375 FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate ); 01376 ctrl2.x += arc[1].x; 01377 ctrl2.y += arc[1].y; 01378 01379 /* compute end point */ 01380 FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate ); 01381 end.x += arc[0].x; 01382 end.y += arc[0].y; 01383 01384 error = ft_stroke_border_cubicto( stroker->borders + side, 01385 &ctrl1, &ctrl2, &end ); 01386 if ( error ) 01387 goto Exit; 01388 } 01389 } 01390 01391 arc -= 3; 01392 if ( arc < bez_stack ) 01393 stroker->angle_in = angle_out; 01394 } 01395 01396 stroker->center = *to; 01397 01398 Exit: 01399 return error; 01400 } 01401 01402 01403 /* documentation is in ftstroke.h */ 01404 01405 FT_EXPORT_DEF( FT_Error ) 01406 FT_Stroker_BeginSubPath( FT_Stroker stroker, 01407 FT_Vector* to, 01408 FT_Bool open ) 01409 { 01410 /* We cannot process the first point, because there is not enough */ 01411 /* information regarding its corner/cap. The latter will be processed */ 01412 /* in the `FT_Stroker_EndSubPath' routine. */ 01413 /* */ 01414 stroker->first_point = TRUE; 01415 stroker->center = *to; 01416 stroker->subpath_open = open; 01417 01418 /* record the subpath start point for each border */ 01419 stroker->subpath_start = *to; 01420 01421 return FT_Err_Ok; 01422 } 01423 01424 01425 static FT_Error 01426 ft_stroker_add_reverse_left( FT_Stroker stroker, 01427 FT_Bool open ) 01428 { 01429 FT_StrokeBorder right = stroker->borders + 0; 01430 FT_StrokeBorder left = stroker->borders + 1; 01431 FT_Int new_points; 01432 FT_Error error = FT_Err_Ok; 01433 01434 01435 FT_ASSERT( left->start >= 0 ); 01436 01437 new_points = left->num_points - left->start; 01438 if ( new_points > 0 ) 01439 { 01440 error = ft_stroke_border_grow( right, (FT_UInt)new_points ); 01441 if ( error ) 01442 goto Exit; 01443 01444 { 01445 FT_Vector* dst_point = right->points + right->num_points; 01446 FT_Byte* dst_tag = right->tags + right->num_points; 01447 FT_Vector* src_point = left->points + left->num_points - 1; 01448 FT_Byte* src_tag = left->tags + left->num_points - 1; 01449 01450 while ( src_point >= left->points + left->start ) 01451 { 01452 *dst_point = *src_point; 01453 *dst_tag = *src_tag; 01454 01455 if ( open ) 01456 dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END; 01457 else 01458 { 01459 FT_Byte ttag = (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END ); 01460 01461 01462 /* switch begin/end tags if necessary */ 01463 if ( ttag == FT_STROKE_TAG_BEGIN || 01464 ttag == FT_STROKE_TAG_END ) 01465 dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END; 01466 01467 } 01468 01469 src_point--; 01470 src_tag--; 01471 dst_point++; 01472 dst_tag++; 01473 } 01474 } 01475 01476 left->num_points = left->start; 01477 right->num_points += new_points; 01478 01479 right->movable = FALSE; 01480 left->movable = FALSE; 01481 } 01482 01483 Exit: 01484 return error; 01485 } 01486 01487 01488 /* documentation is in ftstroke.h */ 01489 01490 /* there's a lot of magic in this function! */ 01491 FT_EXPORT_DEF( FT_Error ) 01492 FT_Stroker_EndSubPath( FT_Stroker stroker ) 01493 { 01494 FT_Error error = FT_Err_Ok; 01495 01496 01497 if ( stroker->subpath_open ) 01498 { 01499 FT_StrokeBorder right = stroker->borders; 01500 01501 /* All right, this is an opened path, we need to add a cap between */ 01502 /* right & left, add the reverse of left, then add a final cap */ 01503 /* between left & right. */ 01504 error = ft_stroker_cap( stroker, stroker->angle_in, 0 ); 01505 if ( error ) 01506 goto Exit; 01507 01508 /* add reversed points from `left' to `right' */ 01509 error = ft_stroker_add_reverse_left( stroker, TRUE ); 01510 if ( error ) 01511 goto Exit; 01512 01513 /* now add the final cap */ 01514 stroker->center = stroker->subpath_start; 01515 error = ft_stroker_cap( stroker, 01516 stroker->subpath_angle + FT_ANGLE_PI, 0 ); 01517 if ( error ) 01518 goto Exit; 01519 01520 /* Now end the right subpath accordingly. The left one is */ 01521 /* rewind and doesn't need further processing. */ 01522 ft_stroke_border_close( right, FALSE ); 01523 } 01524 else 01525 { 01526 FT_Angle turn; 01527 FT_Int inside_side; 01528 01529 /* close the path if needed */ 01530 if ( stroker->center.x != stroker->subpath_start.x || 01531 stroker->center.y != stroker->subpath_start.y ) 01532 { 01533 error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); 01534 if ( error ) 01535 goto Exit; 01536 } 01537 01538 /* process the corner */ 01539 stroker->angle_out = stroker->subpath_angle; 01540 turn = FT_Angle_Diff( stroker->angle_in, 01541 stroker->angle_out ); 01542 01543 /* no specific corner processing is required if the turn is 0 */ 01544 if ( turn != 0 ) 01545 { 01546 /* when we turn to the right, the inside side is 0 */ 01547 inside_side = 0; 01548 01549 /* otherwise, the inside side is 1 */ 01550 if ( turn < 0 ) 01551 inside_side = 1; 01552 01553 error = ft_stroker_inside( stroker, inside_side ); 01554 if ( error ) 01555 goto Exit; 01556 01557 /* process the outside side */ 01558 error = ft_stroker_outside( stroker, 1 - inside_side ); 01559 if ( error ) 01560 goto Exit; 01561 } 01562 01563 /* then end our two subpaths */ 01564 ft_stroke_border_close( stroker->borders + 0, TRUE ); 01565 ft_stroke_border_close( stroker->borders + 1, FALSE ); 01566 } 01567 01568 Exit: 01569 return error; 01570 } 01571 01572 01573 /* documentation is in ftstroke.h */ 01574 01575 FT_EXPORT_DEF( FT_Error ) 01576 FT_Stroker_GetBorderCounts( FT_Stroker stroker, 01577 FT_StrokerBorder border, 01578 FT_UInt *anum_points, 01579 FT_UInt *anum_contours ) 01580 { 01581 FT_UInt num_points = 0, num_contours = 0; 01582 FT_Error error; 01583 01584 01585 if ( !stroker || border > 1 ) 01586 { 01587 error = FT_Err_Invalid_Argument; 01588 goto Exit; 01589 } 01590 01591 error = ft_stroke_border_get_counts( stroker->borders + border, 01592 &num_points, &num_contours ); 01593 Exit: 01594 if ( anum_points ) 01595 *anum_points = num_points; 01596 01597 if ( anum_contours ) 01598 *anum_contours = num_contours; 01599 01600 return error; 01601 } 01602 01603 01604 /* documentation is in ftstroke.h */ 01605 01606 FT_EXPORT_DEF( FT_Error ) 01607 FT_Stroker_GetCounts( FT_Stroker stroker, 01608 FT_UInt *anum_points, 01609 FT_UInt *anum_contours ) 01610 { 01611 FT_UInt count1, count2, num_points = 0; 01612 FT_UInt count3, count4, num_contours = 0; 01613 FT_Error error; 01614 01615 01616 error = ft_stroke_border_get_counts( stroker->borders + 0, 01617 &count1, &count2 ); 01618 if ( error ) 01619 goto Exit; 01620 01621 error = ft_stroke_border_get_counts( stroker->borders + 1, 01622 &count3, &count4 ); 01623 if ( error ) 01624 goto Exit; 01625 01626 num_points = count1 + count3; 01627 num_contours = count2 + count4; 01628 01629 Exit: 01630 *anum_points = num_points; 01631 *anum_contours = num_contours; 01632 return error; 01633 } 01634 01635 01636 /* documentation is in ftstroke.h */ 01637 01638 FT_EXPORT_DEF( void ) 01639 FT_Stroker_ExportBorder( FT_Stroker stroker, 01640 FT_StrokerBorder border, 01641 FT_Outline* outline ) 01642 { 01643 if ( border == FT_STROKER_BORDER_LEFT || 01644 border == FT_STROKER_BORDER_RIGHT ) 01645 { 01646 FT_StrokeBorder sborder = & stroker->borders[border]; 01647 01648 01649 if ( sborder->valid ) 01650 ft_stroke_border_export( sborder, outline ); 01651 } 01652 } 01653 01654 01655 /* documentation is in ftstroke.h */ 01656 01657 FT_EXPORT_DEF( void ) 01658 FT_Stroker_Export( FT_Stroker stroker, 01659 FT_Outline* outline ) 01660 { 01661 FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline ); 01662 FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline ); 01663 } 01664 01665 01666 /* documentation is in ftstroke.h */ 01667 01668 /* 01669 * The following is very similar to FT_Outline_Decompose, except 01670 * that we do support opened paths, and do not scale the outline. 01671 */ 01672 FT_EXPORT_DEF( FT_Error ) 01673 FT_Stroker_ParseOutline( FT_Stroker stroker, 01674 FT_Outline* outline, 01675 FT_Bool opened ) 01676 { 01677 FT_Vector v_last; 01678 FT_Vector v_control; 01679 FT_Vector v_start; 01680 01681 FT_Vector* point; 01682 FT_Vector* limit; 01683 char* tags; 01684 01685 FT_Error error; 01686 01687 FT_Int n; /* index of contour in outline */ 01688 FT_UInt first; /* index of first point in contour */ 01689 FT_Int tag; /* current point's state */ 01690 01691 01692 if ( !outline || !stroker ) 01693 return FT_Err_Invalid_Argument; 01694 01695 FT_Stroker_Rewind( stroker ); 01696 01697 first = 0; 01698 01699 for ( n = 0; n < outline->n_contours; n++ ) 01700 { 01701 FT_UInt last; /* index of last point in contour */ 01702 01703 01704 last = outline->contours[n]; 01705 limit = outline->points + last; 01706 01707 /* skip empty points; we don't stroke these */ 01708 if ( last <= first ) 01709 { 01710 first = last + 1; 01711 continue; 01712 } 01713 01714 v_start = outline->points[first]; 01715 v_last = outline->points[last]; 01716 01717 v_control = v_start; 01718 01719 point = outline->points + first; 01720 tags = outline->tags + first; 01721 tag = FT_CURVE_TAG( tags[0] ); 01722 01723 /* A contour cannot start with a cubic control point! */ 01724 if ( tag == FT_CURVE_TAG_CUBIC ) 01725 goto Invalid_Outline; 01726 01727 /* check first point to determine origin */ 01728 if ( tag == FT_CURVE_TAG_CONIC ) 01729 { 01730 /* First point is conic control. Yes, this happens. */ 01731 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 01732 { 01733 /* start at last point if it is on the curve */ 01734 v_start = v_last; 01735 limit--; 01736 } 01737 else 01738 { 01739 /* if both first and last points are conic, */ 01740 /* start at their middle */ 01741 v_start.x = ( v_start.x + v_last.x ) / 2; 01742 v_start.y = ( v_start.y + v_last.y ) / 2; 01743 } 01744 point--; 01745 tags--; 01746 } 01747 01748 error = FT_Stroker_BeginSubPath( stroker, &v_start, opened ); 01749 if ( error ) 01750 goto Exit; 01751 01752 while ( point < limit ) 01753 { 01754 point++; 01755 tags++; 01756 01757 tag = FT_CURVE_TAG( tags[0] ); 01758 switch ( tag ) 01759 { 01760 case FT_CURVE_TAG_ON: /* emit a single line_to */ 01761 { 01762 FT_Vector vec; 01763 01764 01765 vec.x = point->x; 01766 vec.y = point->y; 01767 01768 error = FT_Stroker_LineTo( stroker, &vec ); 01769 if ( error ) 01770 goto Exit; 01771 continue; 01772 } 01773 01774 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 01775 v_control.x = point->x; 01776 v_control.y = point->y; 01777 01778 Do_Conic: 01779 if ( point < limit ) 01780 { 01781 FT_Vector vec; 01782 FT_Vector v_middle; 01783 01784 01785 point++; 01786 tags++; 01787 tag = FT_CURVE_TAG( tags[0] ); 01788 01789 vec = point[0]; 01790 01791 if ( tag == FT_CURVE_TAG_ON ) 01792 { 01793 error = FT_Stroker_ConicTo( stroker, &v_control, &vec ); 01794 if ( error ) 01795 goto Exit; 01796 continue; 01797 } 01798 01799 if ( tag != FT_CURVE_TAG_CONIC ) 01800 goto Invalid_Outline; 01801 01802 v_middle.x = ( v_control.x + vec.x ) / 2; 01803 v_middle.y = ( v_control.y + vec.y ) / 2; 01804 01805 error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle ); 01806 if ( error ) 01807 goto Exit; 01808 01809 v_control = vec; 01810 goto Do_Conic; 01811 } 01812 01813 error = FT_Stroker_ConicTo( stroker, &v_control, &v_start ); 01814 goto Close; 01815 01816 default: /* FT_CURVE_TAG_CUBIC */ 01817 { 01818 FT_Vector vec1, vec2; 01819 01820 01821 if ( point + 1 > limit || 01822 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 01823 goto Invalid_Outline; 01824 01825 point += 2; 01826 tags += 2; 01827 01828 vec1 = point[-2]; 01829 vec2 = point[-1]; 01830 01831 if ( point <= limit ) 01832 { 01833 FT_Vector vec; 01834 01835 01836 vec = point[0]; 01837 01838 error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); 01839 if ( error ) 01840 goto Exit; 01841 continue; 01842 } 01843 01844 error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start ); 01845 goto Close; 01846 } 01847 } 01848 } 01849 01850 Close: 01851 if ( error ) 01852 goto Exit; 01853 01854 error = FT_Stroker_EndSubPath( stroker ); 01855 if ( error ) 01856 goto Exit; 01857 01858 first = last + 1; 01859 } 01860 01861 return FT_Err_Ok; 01862 01863 Exit: 01864 return error; 01865 01866 Invalid_Outline: 01867 return FT_Err_Invalid_Outline; 01868 } 01869 01870 /* declare an extern to access ft_outline_glyph_class global allocated 01871 in ftglyph.c, and use the FT_OUTLINE_GLYPH_CLASS_GET macro to access 01872 it when FT_CONFIG_OPTION_PIC is defined */ 01873 #ifndef FT_CONFIG_OPTION_PIC 01874 extern const FT_Glyph_Class ft_outline_glyph_class; 01875 #endif 01876 #include "basepic.h" 01877 01878 01879 /* documentation is in ftstroke.h */ 01880 01881 FT_EXPORT_DEF( FT_Error ) 01882 FT_Glyph_Stroke( FT_Glyph *pglyph, 01883 FT_Stroker stroker, 01884 FT_Bool destroy ) 01885 { 01886 FT_Error error = FT_Err_Invalid_Argument; 01887 FT_Glyph glyph = NULL; 01888 FT_Library library = stroker->library; 01889 FT_UNUSED(library); 01890 01891 if ( pglyph == NULL ) 01892 goto Exit; 01893 01894 glyph = *pglyph; 01895 if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET ) 01896 goto Exit; 01897 01898 { 01899 FT_Glyph copy; 01900 01901 01902 error = FT_Glyph_Copy( glyph, © ); 01903 if ( error ) 01904 goto Exit; 01905 01906 glyph = copy; 01907 } 01908 01909 { 01910 FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph; 01911 FT_Outline* outline = &oglyph->outline; 01912 FT_UInt num_points, num_contours; 01913 01914 01915 error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); 01916 if ( error ) 01917 goto Fail; 01918 01919 (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); 01920 01921 FT_Outline_Done( glyph->library, outline ); 01922 01923 error = FT_Outline_New( glyph->library, 01924 num_points, num_contours, outline ); 01925 if ( error ) 01926 goto Fail; 01927 01928 outline->n_points = 0; 01929 outline->n_contours = 0; 01930 01931 FT_Stroker_Export( stroker, outline ); 01932 } 01933 01934 if ( destroy ) 01935 FT_Done_Glyph( *pglyph ); 01936 01937 *pglyph = glyph; 01938 goto Exit; 01939 01940 Fail: 01941 FT_Done_Glyph( glyph ); 01942 glyph = NULL; 01943 01944 if ( !destroy ) 01945 *pglyph = NULL; 01946 01947 Exit: 01948 return error; 01949 } 01950 01951 01952 /* documentation is in ftstroke.h */ 01953 01954 FT_EXPORT_DEF( FT_Error ) 01955 FT_Glyph_StrokeBorder( FT_Glyph *pglyph, 01956 FT_Stroker stroker, 01957 FT_Bool inside, 01958 FT_Bool destroy ) 01959 { 01960 FT_Error error = FT_Err_Invalid_Argument; 01961 FT_Glyph glyph = NULL; 01962 FT_Library library = stroker->library; 01963 FT_UNUSED(library); 01964 01965 if ( pglyph == NULL ) 01966 goto Exit; 01967 01968 glyph = *pglyph; 01969 if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET ) 01970 goto Exit; 01971 01972 { 01973 FT_Glyph copy; 01974 01975 01976 error = FT_Glyph_Copy( glyph, © ); 01977 if ( error ) 01978 goto Exit; 01979 01980 glyph = copy; 01981 } 01982 01983 { 01984 FT_OutlineGlyph oglyph = (FT_OutlineGlyph) glyph; 01985 FT_StrokerBorder border; 01986 FT_Outline* outline = &oglyph->outline; 01987 FT_UInt num_points, num_contours; 01988 01989 01990 border = FT_Outline_GetOutsideBorder( outline ); 01991 if ( inside ) 01992 { 01993 if ( border == FT_STROKER_BORDER_LEFT ) 01994 border = FT_STROKER_BORDER_RIGHT; 01995 else 01996 border = FT_STROKER_BORDER_LEFT; 01997 } 01998 01999 error = FT_Stroker_ParseOutline( stroker, outline, FALSE ); 02000 if ( error ) 02001 goto Fail; 02002 02003 (void)FT_Stroker_GetBorderCounts( stroker, border, 02004 &num_points, &num_contours ); 02005 02006 FT_Outline_Done( glyph->library, outline ); 02007 02008 error = FT_Outline_New( glyph->library, 02009 num_points, 02010 num_contours, 02011 outline ); 02012 if ( error ) 02013 goto Fail; 02014 02015 outline->n_points = 0; 02016 outline->n_contours = 0; 02017 02018 FT_Stroker_ExportBorder( stroker, border, outline ); 02019 } 02020 02021 if ( destroy ) 02022 FT_Done_Glyph( *pglyph ); 02023 02024 *pglyph = glyph; 02025 goto Exit; 02026 02027 Fail: 02028 FT_Done_Glyph( glyph ); 02029 glyph = NULL; 02030 02031 if ( !destroy ) 02032 *pglyph = NULL; 02033 02034 Exit: 02035 return error; 02036 } 02037 02038 02039 /* END */ Generated on Sun May 27 2012 04:33:47 for ReactOS by
1.7.6.1
|