[autofit] Improve handling of `near' points.

Points which are very near to each other are now marked as such.
The `weak' flag is then computed by using the `in' vector of the
first and the `out' vector of the last point of a group of near
points.

For example, this fixes the rendering of glyph `Oslash' in
`Roboto-Thin.ttf'.

* src/autofit/afhints.h (AF_Flags): New value `AF_FLAGS_NEAR'.

* src/autofit/afhints.c (af_glyph_hints_reload): Introduce
the heuristic value `near_limit' to decide whether the current point
is near to the previous one, then set `AF_FLAG_NEAR' accordingly.
Store good `in' vector (of last non-near point) in
`last_good_in_{x,y}' and use it as an argument to
`ft_corner_is_flat' if necessary.
This commit is contained in:
Werner Lemberg 2013-08-05 08:46:15 +02:00
parent ba9cf52d3b
commit cc25e3ae12
3 changed files with 100 additions and 6 deletions

View File

@ -1,3 +1,24 @@
2013-08-05 Werner Lemberg <wl@gnu.org>
[autofit] Improve handling of `near' points.
Points which are very near to each other are now marked as such.
The `weak' flag is then computed by using the `in' vector of the
first and the `out' vector of the last point of a group of near
points.
For example, this fixes the rendering of glyph `Oslash' in
`Roboto-Thin.ttf'.
* src/autofit/afhints.h (AF_Flags): New value `AF_FLAGS_NEAR'.
* src/autofit/afhints.c (af_glyph_hints_reload): Introduce
the heuristic value `near_limit' to decide whether the current point
is near to the previous one, then set `AF_FLAG_NEAR' accordingly.
Store good `in' vector (of last non-near point) in
`last_good_in_{x,y}' and use it as an argument to
`ft_corner_is_flat' if necessary.
2013-08-02 Werner Lemberg <wl@gnu.org>
* include/freetype/ftcffdrv.h: Improve documentation.

View File

@ -740,6 +740,12 @@
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;
FT_UInt units_per_em = hints->metrics->scaler.face->units_per_EM;
FT_Int near_limit = 20 * units_per_em / 2048;
for ( point = points; point < point_limit; point++ )
{
@ -749,15 +755,59 @@
if ( point == first )
{
prev = first->prev;
in_x = first->fx - prev->fx;
in_y = first->fy - prev->fy;
prev = first->prev;
in_x = first->fx - prev->fx;
in_y = first->fy - prev->fy;
last_good_in_x = in_x;
last_good_in_y = in_y;
if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit )
{
/* search first non-near point to get a good `in_dir' value */
AF_Point point_ = prev;
while ( point_ != first )
{
AF_Point prev_ = point_->prev;
FT_Pos in_x_ = point_->fx - prev_->fx;
FT_Pos in_y_ = point_->fy - prev_->fy;
if ( FT_ABS( in_x_ ) + FT_ABS( in_y_) >= near_limit )
{
last_good_in_x = in_x_;
last_good_in_y = in_y_;
break;
}
point_ = prev_;
}
}
in_dir = af_direction_compute( in_x, in_y );
first = prev + 1;
}
point->in_dir = (FT_Char)in_dir;
/* 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) */
if ( FT_ABS( in_x ) + FT_ABS( in_y ) < near_limit )
point->flags |= AF_FLAG_NEAR;
else
{
last_good_in_x = in_x;
last_good_in_y = in_y;
}
next = point->next;
out_x = next->fx - point->fx;
out_y = next->fy - point->fy;
@ -765,23 +815,43 @@
in_dir = af_direction_compute( out_x, out_y );
point->out_dir = (FT_Char)in_dir;
/* check for weak points */
/* Check for weak points. The remaining points not collected */
/* in edges are then implicitly classified as strong points. */
if ( point->flags & AF_FLAG_CONTROL )
{
/* control points are always weak */
Is_Weak_Point:
point->flags |= AF_FLAG_WEAK_INTERPOLATION;
}
else if ( point->out_dir == point->in_dir )
{
if ( point->out_dir != AF_DIR_NONE )
{
/* current point lies on a horizontal or */
/* vertical segment (but doesn't start it) */
goto Is_Weak_Point;
}
if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
/* 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;
}
}
else if ( point->in_dir == -point->out_dir )
{
/* current point forms a spike */
goto Is_Weak_Point;
}
in_x = out_x;
in_y = out_y;

View File

@ -236,7 +236,10 @@ FT_BEGIN_HEADER
AF_FLAG_WEAK_INTERPOLATION = 1 << 8,
/* all inflection points in the outline have this flag set */
AF_FLAG_INFLECTION = 1 << 9
AF_FLAG_INFLECTION = 1 << 9,
/* the current point is very near to another one */
AF_FLAG_NEAR = 1 << 10
} AF_Flags;