diff options
Diffstat (limited to 'src/base/ftoutln.c')
-rw-r--r-- | src/base/ftoutln.c | 224 |
1 files changed, 160 insertions, 64 deletions
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c index 76e2b04..9ae276d 100644 --- a/src/base/ftoutln.c +++ b/src/base/ftoutln.c @@ -882,19 +882,9 @@ FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength ) { - return FT_Outline_EmboldenXY( outline, strength, strength ); - } - - - /* documentation is in ftoutln.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_Outline_EmboldenXY( FT_Outline* outline, - FT_Pos xstrength, - FT_Pos ystrength ) - { FT_Vector* points; FT_Vector v_prev, v_first, v_next, v_cur; + FT_Angle rotate, angle_in, angle_out; FT_Int c, n, first; FT_Int orientation; @@ -902,9 +892,8 @@ if ( !outline ) return FT_Err_Invalid_Argument; - xstrength /= 2; - ystrength /= 2; - if ( xstrength == 0 && ystrength == 0 ) + strength /= 2; + if ( strength == 0 ) return FT_Err_Ok; orientation = FT_Outline_Get_Orientation( outline ); @@ -916,63 +905,62 @@ return FT_Err_Ok; } + if ( orientation == FT_ORIENTATION_TRUETYPE ) + rotate = -FT_ANGLE_PI2; + else + rotate = FT_ANGLE_PI2; + points = outline->points; first = 0; for ( c = 0; c < outline->n_contours; c++ ) { - FT_Vector in, out, shift; - FT_Fixed l_in, l_out, d; - int last = outline->contours[c]; + int last = outline->contours[c]; v_first = points[first]; v_prev = points[last]; v_cur = v_first; - /* compute the incoming vector and its length */ - in.x = v_cur.x - v_prev.x; - in.y = v_cur.y - v_prev.y; - l_in = FT_Vector_Length( &in ); - for ( n = first; n <= last; n++ ) { + FT_Vector in, out; + FT_Angle angle_diff; + FT_Pos d; + FT_Fixed scale; + + if ( n < last ) v_next = points[n + 1]; else v_next = v_first; - /* compute the outgoing vector and its length */ + /* compute the in and out vectors */ + in.x = v_cur.x - v_prev.x; + in.y = v_cur.y - v_prev.y; + out.x = v_next.x - v_cur.x; out.y = v_next.y - v_cur.y; - l_out = FT_Vector_Length( &out ); - d = l_in * l_out + in.x * out.x + in.y * out.y; + angle_in = FT_Atan2( in.x, in.y ); + angle_out = FT_Atan2( out.x, out.y ); + angle_diff = FT_Angle_Diff( angle_in, angle_out ); + scale = FT_Cos( angle_diff / 2 ); - /* shift only if turn is less then ~160 degrees */ - if ( 16 * d > l_in * l_out ) + if ( scale < 0x4000L && scale > -0x4000L ) + in.x = in.y = 0; + else { - /* shift components are rotated */ - shift.x = FT_DivFix( l_out * in.y + l_in * out.y, d ); - shift.y = FT_DivFix( l_out * in.x + l_in * out.x, d ); + d = FT_DivFix( strength, scale ); - if ( orientation == FT_ORIENTATION_TRUETYPE ) - shift.x = -shift.x; - else - shift.y = -shift.y; - - shift.x = FT_MulFix( xstrength, shift.x ); - shift.y = FT_MulFix( ystrength, shift.y ); + FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate ); } - else - shift.x = shift.y = 0; - outline->points[n].x = v_cur.x + xstrength + shift.x; - outline->points[n].y = v_cur.y + ystrength + shift.y; + outline->points[n].x = v_cur.x + strength + in.x; + outline->points[n].y = v_cur.y + strength + in.y; - in = out; - l_in = l_out; - v_cur = v_next; + v_prev = v_cur; + v_cur = v_next; } first = last + 1; @@ -987,10 +975,23 @@ FT_EXPORT_DEF( FT_Orientation ) FT_Outline_Get_Orientation( FT_Outline* outline ) { - FT_Vector* points; - FT_Vector v_prev, v_cur; - FT_Int c, n, first; - FT_Pos area = 0; + FT_Pos xmin = 32768L; + FT_Pos xmin_ymin = 32768L; + FT_Pos xmin_ymax = -32768L; + FT_Vector* xmin_first = NULL; + FT_Vector* xmin_last = NULL; + + short* contour; + + FT_Vector* first; + FT_Vector* last; + FT_Vector* prev; + FT_Vector* point; + + int i; + FT_Pos ray_y[3]; + FT_Orientation result[3] = + { FT_ORIENTATION_NONE, FT_ORIENTATION_NONE, FT_ORIENTATION_NONE }; if ( !outline || outline->n_points <= 0 ) @@ -1001,32 +1002,127 @@ /* cubic or quadratic curves, this test deals with the polygon */ /* only which is spanned up by the control points. */ - points = outline->points; - - first = 0; - for ( c = 0; c < outline->n_contours; c++ ) + first = outline->points; + for ( contour = outline->contours; + contour < outline->contours + outline->n_contours; + contour++, first = last + 1 ) { - FT_Int last = outline->contours[c]; + FT_Pos contour_xmin = 32768L; + FT_Pos contour_xmax = -32768L; + FT_Pos contour_ymin = 32768L; + FT_Pos contour_ymax = -32768L; - v_prev = points[last]; + last = outline->points + *contour; - for ( n = first; n <= last; n++ ) + /* skip degenerate contours */ + if ( last < first + 2 ) + continue; + + for ( point = first; point <= last; ++point ) { - v_cur = points[n]; - area += ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ); - v_prev = v_cur; + if ( point->x < contour_xmin ) + contour_xmin = point->x; + + if ( point->x > contour_xmax ) + contour_xmax = point->x; + + if ( point->y < contour_ymin ) + contour_ymin = point->y; + + if ( point->y > contour_ymax ) + contour_ymax = point->y; } - first = last + 1; + if ( contour_xmin < xmin && + contour_xmin != contour_xmax && + contour_ymin != contour_ymax ) + { + xmin = contour_xmin; + xmin_ymin = contour_ymin; + xmin_ymax = contour_ymax; + xmin_first = first; + xmin_last = last; + } } - if ( area > 0 ) - return FT_ORIENTATION_POSTSCRIPT; - else if ( area < 0 ) + if ( xmin == 32768L ) return FT_ORIENTATION_TRUETYPE; - else - return FT_ORIENTATION_NONE; + + ray_y[0] = ( xmin_ymin * 3 + xmin_ymax ) >> 2; + ray_y[1] = ( xmin_ymin + xmin_ymax ) >> 1; + ray_y[2] = ( xmin_ymin + xmin_ymax * 3 ) >> 2; + + for ( i = 0; i < 3; i++ ) + { + FT_Pos left_x; + FT_Pos right_x; + FT_Vector* left1; + FT_Vector* left2; + FT_Vector* right1; + FT_Vector* right2; + + + RedoRay: + left_x = 32768L; + right_x = -32768L; + + left1 = left2 = right1 = right2 = NULL; + + prev = xmin_last; + for ( point = xmin_first; point <= xmin_last; prev = point, ++point ) + { + FT_Pos tmp_x; + + + if ( point->y == ray_y[i] || prev->y == ray_y[i] ) + { + ray_y[i]++; + goto RedoRay; + } + + if ( ( point->y < ray_y[i] && prev->y < ray_y[i] ) || + ( point->y > ray_y[i] && prev->y > ray_y[i] ) ) + continue; + + tmp_x = FT_MulDiv( point->x - prev->x, + ray_y[i] - prev->y, + point->y - prev->y ) + prev->x; + + if ( tmp_x < left_x ) + { + left_x = tmp_x; + left1 = prev; + left2 = point; + } + + if ( tmp_x > right_x ) + { + right_x = tmp_x; + right1 = prev; + right2 = point; + } + } + + if ( left1 && right1 ) + { + if ( left1->y < left2->y && right1->y > right2->y ) + result[i] = FT_ORIENTATION_TRUETYPE; + else if ( left1->y > left2->y && right1->y < right2->y ) + result[i] = FT_ORIENTATION_POSTSCRIPT; + else + result[i] = FT_ORIENTATION_NONE; + } + } + + if ( result[0] != FT_ORIENTATION_NONE && + ( result[0] == result[1] || result[0] == result[2] ) ) + return result[0]; + + if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] ) + return result[1]; + + return FT_ORIENTATION_TRUETYPE; } |