[autofit] Improve Hebrew rendering.

This change introduces a new blue zone property
`AF_BLUE_PROPERTY_LATIN_LONG' to make the auto-hinter ignore short
top segments.

* src/autofit/afblue.dat: Fix Hebrew blue strings.
Use AF_BLUE_PROPERTY_LATIN_LONG for AF_BLUE_STRING_HEBREW_TOP.

* src/autofit/afblue.hin (AF_BLUE_PROPERTY_LATIN_LONG): New macro.

* src/autofit/afblue.c, src/autofit/afblue.h: Updated.

* src/autofit/aflatin.c (af_latin_metrics_init_blues): Handle
`AF_LATIN_IS_LONG_BLUE'.

* src/autofit/aflatin.h (AF_LATIN_IS_LONG_BLUE): New macro.
This commit is contained in:
Werner Lemberg 2013-09-11 23:08:31 +02:00
parent 00ea2a133b
commit 3f542498b2
7 changed files with 215 additions and 21 deletions

View File

@ -1,3 +1,23 @@
2013-09-11 Werner Lemberg <wl@gnu.org>
[autofit] Improve Hebrew rendering.
This change introduces a new blue zone property
`AF_BLUE_PROPERTY_LATIN_LONG' to make the auto-hinter ignore short
top segments.
* src/autofit/afblue.dat: Fix Hebrew blue strings.
Use AF_BLUE_PROPERTY_LATIN_LONG for AF_BLUE_STRING_HEBREW_TOP.
* src/autofit/afblue.hin (AF_BLUE_PROPERTY_LATIN_LONG): New macro.
* src/autofit/afblue.c, src/autofit/afblue.h: Updated.
* src/autofit/aflatin.c (af_latin_metrics_init_blues): Handle
`AF_LATIN_IS_LONG_BLUE'.
* src/autofit/aflatin.h (AF_LATIN_IS_LONG_BLUE): New macro.
2013-08-28 Behdad Esfahbod <behdad@google.com>
[sfnt] Fix frame access while reading WOFF table directory.

View File

@ -36,9 +36,9 @@
'\0',
'p', 'q', 'g', 'j', 'y', /* pqgjy */
'\0',
'\xD7', '\x90', '\xD7', '\x91', '\xD7', '\x9D', '\xD7', '\xA4', '\xD7', '\xA9', '\xD7', '\x93', '\xD7', '\x92', /* אבםפשדג */
'\xD7', '\x91', '\xD7', '\x93', '\xD7', '\x94', '\xD7', '\x97', '\xD7', '\x9A', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', /* בדהחךכםס */
'\0',
'\xD7', '\x90', '\xD7', '\x94', '\xD7', '\x97', '\xD7', '\x9B', '\xD7', '\x9E', '\xD7', '\xA1', /* אהחכמס */
'\xD7', '\x91', '\xD7', '\x98', '\xD7', '\x9B', '\xD7', '\x9D', '\xD7', '\xA1', '\xD7', '\xA6', /* בטכםסצ */
'\0',
'\xD7', '\xA7', '\xD7', '\x9A', '\xD7', '\x9F', '\xD7', '\xA3', '\xD7', '\xA5', /* קךןףץ */
#ifdef AF_CONFIG_OPTION_CJK
@ -103,10 +103,11 @@
{ AF_BLUE_STRING_LATIN_SMALL, 0 },
{ AF_BLUE_STRING_LATIN_SMALL_MINOR, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP },
{ AF_BLUE_STRING_HEBREW_BOTTOM, 0 },
{ AF_BLUE_STRING_HEBREW_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
{ AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_LONG },
{ AF_BLUE_STRING_HEBREW_BOTTOM, 0 },
{ AF_BLUE_STRING_HEBREW_DESCENDER, 0 },
{ AF_BLUE_STRING_MAX, 0 },
#ifdef AF_CONFIG_OPTION_CJK
{ AF_BLUE_STRING_CJK_TOP_FILL, AF_BLUE_PROPERTY_CJK_TOP |
AF_BLUE_PROPERTY_CJK_FILL },

View File

@ -77,9 +77,9 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN:
"pqgjy"
AF_BLUE_STRING_HEBREW_TOP
"אבםפשדג"
"בדהחךכםס"
AF_BLUE_STRING_HEBREW_BOTTOM
"אהחכמס"
"בטכםסצ"
AF_BLUE_STRING_HEBREW_DESCENDER
"קךןףץ"
@ -147,10 +147,11 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN:
{ AF_BLUE_STRING_MAX, 0 }
AF_BLUE_STRINGSET_HEBR
{ AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP }
{ AF_BLUE_STRING_HEBREW_BOTTOM, 0 }
{ AF_BLUE_STRING_HEBREW_DESCENDER, 0 }
{ AF_BLUE_STRING_MAX, 0 }
{ AF_BLUE_STRING_HEBREW_TOP, AF_BLUE_PROPERTY_LATIN_TOP |
AF_BLUE_PROPERTY_LATIN_LONG }
{ AF_BLUE_STRING_HEBREW_BOTTOM, 0 }
{ AF_BLUE_STRING_HEBREW_DESCENDER, 0 }
{ AF_BLUE_STRING_MAX, 0 }
#ifdef AF_CONFIG_OPTION_CJK

View File

@ -80,9 +80,9 @@ FT_BEGIN_HEADER
AF_BLUE_STRING_LATIN_SMALL = 26,
AF_BLUE_STRING_LATIN_SMALL_MINOR = 34,
AF_BLUE_STRING_HEBREW_TOP = 40,
AF_BLUE_STRING_HEBREW_BOTTOM = 55,
AF_BLUE_STRING_HEBREW_DESCENDER = 68,
af_blue_1_1 = 78,
AF_BLUE_STRING_HEBREW_BOTTOM = 57,
AF_BLUE_STRING_HEBREW_DESCENDER = 70,
af_blue_1_1 = 80,
#ifdef AF_CONFIG_OPTION_CJK
AF_BLUE_STRING_CJK_TOP_FILL = af_blue_1_1 + 1,
AF_BLUE_STRING_CJK_TOP_UNFILL = af_blue_1_1 + 77,
@ -129,6 +129,7 @@ FT_BEGIN_HEADER
/* is a safe bet. */
#define AF_BLUE_PROPERTY_LATIN_TOP ( 1 << 0 )
#define AF_BLUE_PROPERTY_LATIN_SMALL_TOP ( 1 << 1 )
#define AF_BLUE_PROPERTY_LATIN_LONG ( 1 << 2 )
#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1 << 0 )
#define AF_BLUE_PROPERTY_CJK_TOP ( 1 << 1 )

View File

@ -98,6 +98,7 @@ FT_BEGIN_HEADER
/* is a safe bet. */
#define AF_BLUE_PROPERTY_LATIN_TOP ( 1 << 0 )
#define AF_BLUE_PROPERTY_LATIN_SMALL_TOP ( 1 << 1 )
#define AF_BLUE_PROPERTY_LATIN_LONG ( 1 << 2 )
#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1 << 0 )
#define AF_BLUE_PROPERTY_CJK_TOP ( 1 << 1 )

View File

@ -219,9 +219,7 @@
/* we walk over the blue character strings as specified in the */
/* script's entry in the `af_blue_stringset' array, finding its */
/* top-most or bottom-most points (depending on the string */
/* properties) */
/* script's entry in the `af_blue_stringset' array */
FT_TRACE5(( "latin blue zones computation\n"
"============================\n"
@ -290,7 +288,7 @@
/* Avoid single-point contours since they are never rasterized. */
/* In some fonts, they correspond to mark attachment points */
/* which are way outside of the glyph's real outline. */
/* that are way outside of the glyph's real outline. */
if ( last <= first )
continue;
@ -319,8 +317,6 @@
best_contour_last = last;
}
}
FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
}
/* now check whether the point belongs to a straight or round */
@ -403,6 +399,178 @@
} while ( next != best_point );
if ( AF_LATIN_IS_LONG_BLUE( bs ) )
{
/* If this flag is set, we have an additional constraint to */
/* get the blue zone distance: Find a segment of the topmost */
/* (or bottommost) contour that is longer than a heuristic */
/* threshold. This ensures that small bumps in the outline */
/* are ignored (for example, the `vertical serifs' found in */
/* many Hebrew glyph designs). */
/* If this segment is long enough, we are done. Otherwise, */
/* search the segment next to the extremum that is long */
/* enough, has the same direction, and a not too large */
/* vertical distance from the extremum. Note that the */
/* algorithm doesn't check whether the found segment is */
/* actually the one (vertically) nearest to the extremum. */
/* heuristic threshold value */
FT_Pos length_threshold = metrics->units_per_em / 25;
dist = FT_ABS( points[best_segment_last].x -
points[best_segment_first].x );
if ( dist < length_threshold &&
best_segment_last - best_segment_first + 2 <=
best_contour_last - best_contour_first )
{
/* heuristic threshold value */
FT_Pos height_threshold = metrics->units_per_em / 4;
FT_Int first;
FT_Int last;
FT_Bool hit;
FT_Bool left2right;
/* compute direction */
prev = best_point;
do
{
if ( prev > best_contour_first )
prev--;
else
prev = best_contour_last;
if ( points[prev].x != best_x )
break;
} while ( prev != best_point );
/* skip glyph for the degenerate case */
if ( prev == best_point )
continue;
left2right = FT_BOOL( points[prev].x < points[best_point].x );
first = best_segment_last;
last = first;
hit = 0;
do
{
FT_Bool l2r;
FT_Pos d;
FT_Int p_first, p_last;
if ( !hit )
{
/* no hit; adjust first point */
first = last;
/* also adjust first and last on point */
if ( FT_CURVE_TAG( outline.tags[first] ) ==
FT_CURVE_TAG_ON )
{
p_first = first;
p_last = first;
}
else
{
p_first = -1;
p_last = -1;
}
hit = 1;
}
if ( last < best_contour_last )
last++;
else
last = best_contour_first;
if ( FT_ABS( best_y - points[first].y ) > height_threshold )
{
/* vertical distance too large */
hit = 0;
continue;
}
/* same test as above */
dist = FT_ABS( points[last].y - points[first].y );
if ( dist > 5 )
if ( FT_ABS( points[last].x - points[first].x ) <=
20 * dist )
{
hit = 0;
continue;
}
if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
{
p_last = last;
if ( p_first < 0 )
p_first = last;
}
l2r = FT_BOOL( points[first].x < points[last].x );
d = FT_ABS( points[last].x - points[first].x );
if ( l2r == left2right &&
d >= length_threshold )
{
/* all constraints are met; update segment after finding */
/* its end */
do
{
if ( last < best_contour_last )
last++;
else
last = best_contour_first;
d = FT_ABS( points[last].y - points[first].y );
if ( d > 5 )
if ( FT_ABS( points[next].x - points[first].x ) <=
20 * dist )
{
last--;
break;
}
p_last = last;
if ( FT_CURVE_TAG( outline.tags[last] ) ==
FT_CURVE_TAG_ON )
{
p_last = last;
if ( p_first < 0 )
p_first = last;
}
} while ( last != best_segment_first );
best_y = points[first].y;
best_segment_first = first;
best_segment_last = last;
best_on_point_first = p_first;
best_on_point_last = p_last;
break;
}
} while ( last != best_segment_first );
}
}
FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
/* now set the `round' flag depending on the segment's kind: */
/* */
/* - if the horizontal distance between the first and last */

View File

@ -65,6 +65,8 @@ FT_BEGIN_HEADER
( (b)->properties & AF_BLUE_PROPERTY_LATIN_TOP )
#define AF_LATIN_IS_SMALL_TOP_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_SMALL_TOP )
#define AF_LATIN_IS_LONG_BLUE( b ) \
( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG )
#define AF_LATIN_MAX_WIDTHS 16