@ -698,91 +698,165 @@
}
}
/* compute directions of in & out vectors */
{
AF_Point first = points ;
AF_Point prev = NULL ;
FT_Pos in_x = 0 ;
FT_Pos in_y = 0 ;
AF_Direction in_dir = AF_DIR_NONE ;
FT_Pos last_good_in_x = 0 ;
FT_Pos last_good_in_y = 0 ;
/*
* Compute directions of ` in ' and ` out ' vectors .
*
* Note that distances between points that are very near to each
* other are accumulated . In other words , the auto - hinter
* prepends the small vectors between near points to the first
* non - near vector . All intermediate points are tagged as
* weak ; the directions are adjusted also to be equal to the
* accumulated one .
*/
/* value 20 in `near_limit' is heuristic */
FT_UInt units_per_em = hints - > metrics - > scaler . face - > units_per_EM ;
FT_Int near_limit = 20 * units_per_em / 2048 ;
AF_Point * contour ;
AF_Point * contour_limit = hints - > contours + hints - > num_contours ;
for ( point = points ; point < point_limit ; point + + )
for ( contour = hints - > contours ; contour < contour_limit ; contour + + )
{
AF_Point next ;
FT_Pos out_x , out_y ;
AF_Point first = * contour ;
AF_Point next , prev , curr ;
FT_Pos out_x , out_y ;
FT_Bool is_first ;
if ( point = = first )
/* since the first point of a contour could be part of a */
/* series of near points, go backwards to find the first */
/* non-near point and adjust `first' */
point = first ;
prev = first - > prev ;
while ( prev ! = first )
{
prev = first - > prev ;
out_x = point - > fx - prev - > fx ;
out_y = point - > fy - prev - > fy ;
in_x = first - > fx - prev - > fx ;
in_y = first - > fy - prev - > fy ;
/* we use Taxicab metrics to measure the vector length */
if ( FT_ABS ( out_x ) + FT_ABS ( out_y ) > = near_limit )
break ;
last_good_in_x = in_x ;
last_good_in_y = in_y ;
point = prev ;
prev = prev - > prev ;
}
if ( FT_ABS ( in_x ) + FT_ABS ( in_y ) < near_limit )
{
/* search first non-near point to get a good `in_dir' value */
/* adjust first point */
first = point ;
AF_Point point_ = prev ;
/* now loop over all points of the contour to get */
/* `in' and `out' vector directions */
curr = first ;
out_x = 0 ;
out_y = 0 ;
while ( point_ ! = first )
{
AF_Point prev_ = point_ - > prev ;
is_first = 1 ;
FT_Pos in_x_ = point_ - > fx - prev_ - > fx ;
FT_Pos in_y_ = point_ - > fy - prev_ - > fy ;
for ( point = first ;
point ! = first | | is_first ;
point = point - > next )
{
AF_Direction out_dir ;
if ( FT_ABS ( in_x_ ) + FT_ABS ( in_y_ ) > = near_limit )
{
last_good_in_x = in_x_ ;
last_good_in_y = in_y_ ;
is_first = 0 ;
break ;
}
next = point - > next ;
point_ = prev_ ;
}
out_x + = next - > fx - point - > fx ;
out_y + = next - > fy - point - > fy ;
if ( FT_ABS ( out_x ) + FT_ABS ( out_y ) < near_limit )
{
next - > flags | = AF_FLAG_WEAK_INTERPOLATION ;
continue ;
}
in_dir = af_direction_compute ( in_x , in_y ) ;
first = prev + 1 ;
/* we abuse the `u' and `v' fields to store index deltas */
/* to the next and previous non-near point, respectively */
curr - > u = ( FT_Pos ) ( next - curr ) ;
next - > v = - curr - > u ;
out_dir = af_direction_compute ( out_x , out_y ) ;
/* adjust directions for all points inbetween; */
/* the loop also updates position of `curr' */
curr - > out_dir = ( FT_Char ) out_dir ;
for ( curr = curr - > next ; curr ! = next ; curr = curr - > next )
{
curr - > in_dir = ( FT_Char ) out_dir ;
curr - > out_dir = ( FT_Char ) out_dir ;
}
next - > in_dir = ( FT_Char ) out_dir ;
out_x = 0 ;
out_y = 0 ;
}
}
point - > in_dir = ( FT_Char ) in_dir ;
/*
* The next step is to ` simplify ' an outline ' s topology so that we
* can identify local extrema more reliably : A series of
* non - horizontal or non - vertical vectors pointing into the same
* quadrant are handled as a single , long vector . From a
* topological point of the view , the intermediate points are of no
* interest and thus tagged as weak .
*/
/* check whether the current point is near to the previous one */
/* (value 20 in `near_limit' is heuristic; we use Taxicab */
/* metrics for the test) */
for ( point = points ; point < point_limit ; point + + )
{
if ( point - > flags & AF_FLAG_WEAK_INTERPOLATION )
continue ;
if ( FT_ABS ( in_x ) + FT_ABS ( in_y ) < near_limit )
point - > flags | = AF_FLAG_NEAR ;
else
if ( point - > in_dir = = AF_DIR_NONE & &
point - > out_dir = = AF_DIR_NONE )
{
last_good_in_x = in_x ;
last_good_in_y = in_y ;
}
/* check whether both vectors point into the same quadrant */
FT_Pos in_x , in_y ;
FT_Pos out_x , out_y ;
AF_Point next_u = point + point - > u ;
AF_Point prev_v = point + point - > v ;
in_x = point - > fx - prev_v - > fx ;
in_y = point - > fy - prev_v - > fy ;
next = point - > next ;
out_x = next - > fx - point - > fx ;
out_y = next - > fy - point - > fy ;
out_x = next_u - > fx - point - > fx ;
out_y = next_u - > fy - point - > fy ;
in_dir = af_direction_compute ( out_x , out_y ) ;
point - > out_dir = ( FT_Char ) in_dir ;
if ( ( in_x ^ out_x ) > = 0 & & ( in_y ^ out_y ) > = 0 )
{
/* yes, so tag current point as weak */
/* and update index deltas */
point - > flags | = AF_FLAG_WEAK_INTERPOLATION ;
prev_v - > u = ( FT_Pos ) ( next_u - prev_v ) ;
next_u - > v = - prev_v - > u ;
}
}
}
/* Check for weak points. The remaining points not collected */
/* in edges are then implicitly classified as strong points. */
/*
* Finally , check for remaining weak points . Everything else not
* collected in edges so far is then implicitly classified as strong
* points .
*/
for ( point = points ; point < point_limit ; point + + )
{
if ( point - > flags & AF_FLAG_WEAK_INTERPOLATION )
continue ;
if ( point - > flags & AF_FLAG_CONTROL )
{
@ -799,18 +873,25 @@
goto Is_Weak_Point ;
}
/* test whether `in' and `out' direction is approximately */
/* the same (and use the last good `in' vector in case */
/* the current point is near to the previous one) */
if ( ft_corner_is_flat (
point - > flags & AF_FLAG_NEAR ? last_good_in_x : in_x ,
point - > flags & AF_FLAG_NEAR ? last_good_in_y : in_y ,
out_x ,
out_y ) )
{
/* current point lies on a straight, diagonal line */
/* (more or less) */
goto Is_Weak_Point ;
AF_Point next_u = point + point - > u ;
AF_Point prev_v = point + point - > v ;
if ( ft_corner_is_flat ( point - > fx - prev_v - > fx ,
point - > fy - prev_v - > fy ,
next_u - > fx - point - > fx ,
next_u - > fy - point - > fy ) )
{
/* either the `in' or the `out' vector is much more */
/* dominant than the other one, so tag current point */
/* as weak and update index deltas */
prev_v - > u = ( FT_Pos ) ( next_u - prev_v ) ;
next_u - > v = - prev_v - > u ;
goto Is_Weak_Point ;
}
}
}
else if ( point - > in_dir = = - point - > out_dir )
@ -818,9 +899,6 @@
/* current point forms a spike */
goto Is_Weak_Point ;
}
in_x = out_x ;
in_y = out_y ;
}
}
}