diff --git a/include/ftimage.h b/include/ftimage.h index 24d2d6b40..01f6bad12 100644 --- a/include/ftimage.h +++ b/include/ftimage.h @@ -467,6 +467,9 @@ FT_Outline_ConicTo_Func conic_to; FT_Outline_CubicTo_Func cubic_to; + int shift; + FT_Pos delta; + } FT_Outline_Funcs; diff --git a/src/base/ftgrays.c b/src/base/ftgrays.c index 927b7a4ae..9362f0bc6 100644 --- a/src/base/ftgrays.c +++ b/src/base/ftgrays.c @@ -1241,7 +1241,9 @@ int check_sort( PCell cells, int count ) (FT_Outline_MoveTo_Func)Move_To, (FT_Outline_LineTo_Func)Line_To, (FT_Outline_ConicTo_Func)Conic_To, - (FT_Outline_CubicTo_Func)Cubic_To + (FT_Outline_CubicTo_Func)Cubic_To, + 0, + 0 }; TBand bands[40], *band; diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c index 43ec6dbea..f63115f6c 100644 --- a/src/base/ftoutln.c +++ b/src/base/ftoutln.c @@ -56,6 +56,195 @@ /* */ /* Error code. 0 means sucess. */ /* */ +#if 1 + + EXPORT_FUNC + int FT_Outline_Decompose( FT_Outline* outline, + FT_Outline_Funcs* interface, + void* user ) + { +#undef SCALED +#define SCALED( x ) ( ((x) << shift) - delta ) + + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + + FT_Vector* point; + FT_Vector* limit; + char* tags; + + int n; /* index of contour in outline */ + int first; /* index of first point in contour */ + int error; + char tag; /* current point's state */ + + int shift = interface->shift; + FT_Pos delta = interface->delta; + + first = 0; + + for ( n = 0; n < outline->n_contours; n++ ) + { + int last; /* index of last point in contour */ + + last = outline->contours[n]; + limit = outline->points + last; + + v_start = outline->points[first]; + v_last = outline->points[last]; + + v_start.x = SCALED(v_start.x); v_start.y = SCALED(v_start.y); + v_last.x = SCALED(v_last.x); v_last.y = SCALED(v_last.y); + + v_control = v_start; + + point = outline->points + first; + tags = outline->tags + first; + tag = FT_CURVE_TAG( tags[0] ); + + /* A contour cannot start with a cubic control point! */ + if ( tag == FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + /* check first point to determine origin */ + if ( tag == FT_Curve_Tag_Conic ) + { + /* first point is conic control. Yes, this happens. */ + if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On ) + { + /* start at last point if it is on the curve */ + v_start = v_last; + limit--; + } + else + { + /* if both first and last points are conic, */ + /* start at their middle and record its position */ + /* for closure */ + v_start.x = ( v_start.x + v_last.x ) / 2; + v_start.y = ( v_start.y + v_last.y ) / 2; + + v_last = v_start; + } + point--; + tags--; + } + + error = interface->move_to( &v_start, user ); + if (error) goto Exit; + + while (point < limit) + { + point++; + tags++; + + tag = FT_CURVE_TAG( tags[0] ); + switch (tag) + { + case FT_Curve_Tag_On: /* emit a single line_to */ + { + FT_Vector vec; + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + error = interface->line_to( &vec, user ); + if (error) goto Exit; + continue; + } + + + case FT_Curve_Tag_Conic: /* consume conic arcs */ + { + v_control.x = SCALED(point->x); + v_control.y = SCALED(point->y); + + Do_Conic: + if (point < limit) + { + FT_Vector vec; + FT_Vector v_middle; + + point++; + tags++; + tag = FT_CURVE_TAG( tags[0] ); + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + if (tag == FT_Curve_Tag_On) + { + error = interface->conic_to( &v_control, &vec, user ); + if (error) goto Exit; + continue; + } + + if (tag != FT_Curve_Tag_Conic) + goto Invalid_Outline; + + v_middle.x = (v_control.x + vec.x)/2; + v_middle.y = (v_control.y + vec.y)/2; + + error = interface->conic_to( &v_control, &v_middle, user ); + if (error) goto Exit; + + v_control = vec; + goto Do_Conic; + } + + error = interface->conic_to( &v_control, &v_start, user ); + goto Close; + } + + default: /* FT_Curve_Tag_Cubic */ + { + FT_Vector vec1, vec2; + + if ( point+1 > limit || + FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic ) + goto Invalid_Outline; + + point += 2; + tags += 2; + + vec1.x = SCALED(point[-2].x); vec1.y = SCALED(point[-2].y); + vec2.x = SCALED(point[-1].x); vec2.y = SCALED(point[-1].y); + + if (point <= limit) + { + FT_Vector vec; + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + error = interface->cubic_to( &vec1, &vec2, &vec, user ); + if (error) goto Exit; + continue; + } + + error = interface->cubic_to( &vec1, &vec2, &v_start, user ); + goto Close; + } + } + } + + /* close the contour with a line segment */ + error = interface->line_to( &v_start, user ); + + Close: + if (error) goto Exit; + first = last+1; + } + + return 0; + Exit: + return error; + + Invalid_Outline: + return -1; + } +#else EXPORT_FUNC int FT_Outline_Decompose( FT_Outline* outline, FT_Outline_Funcs* interface, @@ -224,7 +413,7 @@ Invalid_Outline: return -1; } - +#endif /*************************************************************************/ /* */ diff --git a/src/base/ftraster.c b/src/base/ftraster.c index bac067b0b..82ecd0e2f 100644 --- a/src/base/ftraster.c +++ b/src/base/ftraster.c @@ -2283,7 +2283,9 @@ (FT_Outline_MoveTo_Func)Move_To, (FT_Outline_LineTo_Func)Line_To, (FT_Outline_ConicTo_Func)Conic_To, - (FT_Outline_CubicTo_Func)Cubic_To + (FT_Outline_CubicTo_Func)Cubic_To, + 0, + 0 }; /* Set up state in the raster object */