[autofit] Improve recognition of flat vs. rounded segments.

Lower the flatness threshold from upem/8 to upem/14, making the
auto-hinter accept shorter elements.

Synchronize flat/round stem selection algorithm with blue zone code.

* src/autofit/aflatin.c (FLAT_THRESHOLD): New macro.
(af_latin_metrics_init_blues): Use it.
(af_latin_hints_compute_segments): Collect information on maximum
and minimum coordinates of `on' points; use this to add a constraint
for the flat/round decision similar to
`af_latin_metrics_init_blues'.
This commit is contained in:
Werner Lemberg 2015-08-05 21:53:50 +02:00
parent eb22ef26d9
commit 15e2a4f790
2 changed files with 70 additions and 23 deletions

View File

@ -1,3 +1,19 @@
2015-08-05 Werner Lemberg <wl@gnu.org>
[autofit] Improve recognition of flat vs. rounded segments.
Lower the flatness threshold from upem/8 to upem/14, making the
auto-hinter accept shorter elements.
Synchronize flat/round stem selection algorithm with blue zone code.
* src/autofit/aflatin.c (FLAT_THRESHOLD): New macro.
(af_latin_metrics_init_blues): Use it.
(af_latin_hints_compute_segments): Collect information on maximum
and minimum coordinates of `on' points; use this to add a constraint
for the flat/round decision similar to
`af_latin_metrics_init_blues'.
2015-08-04 Werner Lemberg <wl@gnu.org>
Another left-shift bug (#45681).

View File

@ -41,6 +41,10 @@
#define FT_COMPONENT trace_aflatin
/* needed for computation of round vs. flat segments */
#define FLAT_THRESHOLD( x ) ( x / 14 )
/*************************************************************************/
/*************************************************************************/
/***** *****/
@ -274,6 +278,8 @@
AF_Blue_Stringset bss = sc->blue_stringset;
const AF_Blue_StringRec* bs = &af_blue_stringsets[bss];
FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
/* we walk over the blue character strings as specified in the */
/* style's entry in the `af_blue_stringset' array */
@ -693,16 +699,16 @@
/* now set the `round' flag depending on the segment's kind: */
/* */
/* - if the horizontal distance between the first and last */
/* `on' point is larger than upem/8 (value 8 is heuristic) */
/* `on' point is larger than a heuristic threshold */
/* we have a flat segment */
/* - if either the first or the last point of the segment is */
/* an `off' point, the segment is round, otherwise it is */
/* flat */
if ( best_on_point_first >= 0 &&
best_on_point_last >= 0 &&
(FT_UInt)( FT_ABS( points[best_on_point_last].x -
points[best_on_point_first].x ) ) >
metrics->units_per_em / 8 )
( FT_ABS( points[best_on_point_last].x -
points[best_on_point_first].x ) ) >
flat_threshold )
round = 0;
else
round = FT_BOOL(
@ -1155,14 +1161,17 @@
af_latin_hints_compute_segments( AF_GlyphHints hints,
AF_Dimension dim )
{
AF_AxisHints axis = &hints->axis[dim];
FT_Memory memory = hints->memory;
FT_Error error = FT_Err_Ok;
AF_Segment segment = NULL;
AF_SegmentRec seg0;
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
AF_Direction major_dir, segment_dir;
AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics;
AF_AxisHints axis = &hints->axis[dim];
FT_Memory memory = hints->memory;
FT_Error error = FT_Err_Ok;
AF_Segment segment = NULL;
AF_SegmentRec seg0;
AF_Point* contour = hints->contours;
AF_Point* contour_limit = contour + hints->num_contours;
AF_Direction major_dir, segment_dir;
FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
FT_ZERO( &seg0 );
@ -1203,11 +1212,13 @@
/* do each contour separately */
for ( ; contour < contour_limit; contour++ )
{
AF_Point point = contour[0];
AF_Point last = point->prev;
int on_edge = 0;
FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */
FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
AF_Point point = contour[0];
AF_Point last = point->prev;
int on_edge = 0;
FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */
FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
FT_Pos min_on_pos = 32000;
FT_Pos max_on_pos = -32000;
FT_Bool passed;
@ -1249,6 +1260,16 @@
if ( u > max_pos )
max_pos = u;
/* get minimum and maximum coordinate of on points */
if ( !( point->flags & AF_FLAG_CONTROL ) )
{
v = point->v;
if ( v < min_on_pos )
min_on_pos = v;
if ( v > max_on_pos )
max_on_pos = v;
}
if ( point->out_dir != segment_dir || point == last )
{
/* we are just leaving an edge; record a new segment! */
@ -1256,9 +1277,10 @@
segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
/* a segment is round if either its first or last point */
/* is a control point */
if ( ( segment->first->flags | point->flags ) &
AF_FLAG_CONTROL )
/* is a control point, and the length of the on points */
/* inbetween doesn't exceed a heuristic limit */
if ( ( segment->first->flags | point->flags ) & AF_FLAG_CONTROL &&
( max_on_pos - min_on_pos ) < flat_threshold )
segment->flags |= AF_EDGE_ROUND;
/* compute segment size */
@ -1301,10 +1323,19 @@
/* clear all segment fields */
segment[0] = seg0;
segment->dir = (FT_Char)segment_dir;
segment->dir = (FT_Char)segment_dir;
segment->first = point;
segment->last = point;
min_pos = max_pos = point->u;
segment->first = point;
segment->last = point;
if ( point->flags & AF_FLAG_CONTROL )
{
min_on_pos = 32000;
max_on_pos = -32000;
}
else
min_on_pos = max_on_pos = point->v;
on_edge = 1;
}