ref: cc25e3ae12216380179506b9d5d9c25293966708
parent: ba9cf52d3bbe76d9bb51911443fe9f0b0f069ec2
author: Werner Lemberg <[email protected]>
date: Mon Aug 5 04:46:15 EDT 2013
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2013-08-05 Werner Lemberg <[email protected]>
+
+ [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 <[email protected]>
* include/freetype/ftcffdrv.h: Improve documentation.
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -740,7 +740,13 @@
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++ )
{
AF_Point next;
@@ -749,9 +755,41 @@
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;
}
@@ -758,6 +796,18 @@
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,10 +815,12 @@
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;
}
@@ -775,13 +827,31 @@
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;
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -236,7 +236,10 @@
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;