[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:
parent
00ea2a133b
commit
3f542498b2
20
ChangeLog
20
ChangeLog
@ -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.
|
||||
|
@ -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 },
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -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 )
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user