ref: 3f542498b2c3d480238bd14fad76e1c3ef83f1b4
parent: 00ea2a133b377d74f9694d3ba74588a4e8542120
author: Werner Lemberg <[email protected]>
date: Wed Sep 11 19:08:31 EDT 2013
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2013-09-11 Werner Lemberg <[email protected]>
+
+ [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 <[email protected]>
[sfnt] Fix frame access while reading WOFF table directory.
--- a/src/autofit/afblue.c
+++ b/src/autofit/afblue.c
@@ -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 },
--- a/src/autofit/afblue.dat
+++ b/src/autofit/afblue.dat
@@ -77,9 +77,9 @@
"pqgjy"
AF_BLUE_STRING_HEBREW_TOP
- "אבםפשדג"
+ "בדהחךכםס"
AF_BLUE_STRING_HEBREW_BOTTOM
- "אהחכמס"
+ "בטכםסצ"
AF_BLUE_STRING_HEBREW_DESCENDER
"קךןףץ"
@@ -147,10 +147,11 @@
{ 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
--- a/src/autofit/afblue.h
+++ b/src/autofit/afblue.h
@@ -80,9 +80,9 @@
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 @@
/* 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 )
--- a/src/autofit/afblue.hin
+++ b/src/autofit/afblue.hin
@@ -98,6 +98,7 @@
/* 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 )
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -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 */
@@ -402,6 +398,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: */
/* */
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -65,6 +65,8 @@
( (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