ref: be32b168ac42e670e1a8c5c614cce4c3f8232829
parent: 7363414b9d77eff0fb4d22645cda8e2a0606d66e
author: Philipp Knechtges <[email protected]>
date: Sun Nov 8 03:37:51 EST 2015
[autofit] Don't distort (latin) glyphs too much (#46195). * src/autofit/aflatin.h (AF_LatinBlueRec): Add `ascender' and `descender' fields. * src/autofit/aflatin.c (af_latin_metrics_init_blues): Collect ascender and descender data for blue zones. (af_latin_metrics_scale_dim): Reject vertical scaling values that change the result by more than two pixels.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2015-11-06 Philipp Knechtges <[email protected]>
+
+ [autofit] Don't distort (latin) glyphs too much (#46195).
+
+ * src/autofit/aflatin.h (AF_LatinBlueRec): Add `ascender' and
+ `descender' fields.
+
+ * src/autofit/aflatin.c (af_latin_metrics_init_blues): Collect
+ ascender and descender data for blue zones.
+ (af_latin_metrics_scale_dim): Reject vertical scaling values that
+ change the result by more than two pixels.
+
2015-11-05 Werner Lemberg <[email protected]>
[sfnt] Ignore embedded bitmaps with zero size (#46379).
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -293,6 +293,8 @@
const char* p = &af_blue_strings[bs->string];
FT_Pos* blue_ref;
FT_Pos* blue_shoot;
+ FT_Pos ascender;
+ FT_Pos descender;
#ifdef FT_DEBUG_LEVEL_TRACE
@@ -344,6 +346,8 @@
num_flats = 0;
num_rounds = 0;
+ ascender = 0;
+ descender = 0;
while ( *p )
{
@@ -405,20 +409,30 @@
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
{
for ( pp = first; pp <= last; pp++ )
+ {
if ( best_point < 0 || points[pp].y > best_y )
{
best_point = pp;
best_y = points[pp].y;
+ ascender = FT_MAX( ascender, best_y + y_offset );
}
+ else
+ descender = FT_MIN( descender, points[pp].y + y_offset );
+ }
}
else
{
for ( pp = first; pp <= last; pp++ )
+ {
if ( best_point < 0 || points[pp].y < best_y )
{
best_point = pp;
best_y = points[pp].y;
+ descender = FT_MIN( descender, best_y + y_offset );
}
+ else
+ ascender = FT_MAX( ascender, points[pp].y + y_offset );
+ }
}
if ( best_point != old_best_point )
@@ -791,6 +805,9 @@
}
}
+ blue->ascender = ascender;
+ blue->descender = descender;
+
blue->flags = 0;
if ( AF_LATIN_IS_TOP_BLUE( bs ) )
blue->flags |= AF_LATIN_BLUE_TOP;
@@ -973,18 +990,52 @@
#endif
if ( dim == AF_DIMENSION_VERT )
{
- scale = FT_MulDiv( scale, fitted, scaled );
+ FT_Pos max_height;
+ FT_Pos dist;
+ FT_Fixed new_scale;
- FT_TRACE5((
- "af_latin_metrics_scale_dim:"
- " x height alignment (style `%s'):\n"
- " "
- " vertical scaling changed from %.4f to %.4f (by %d%%)\n"
- "\n",
- af_style_names[metrics->root.style_class->style],
- axis->org_scale / 65536.0,
- scale / 65536.0,
- ( fitted - scaled ) * 100 / scaled ));
+
+ new_scale = FT_MulDiv( scale, fitted, scaled );
+
+ /* the scaling should not change the result by more than two pixels */
+ max_height = metrics->units_per_em;
+
+ for ( nn = 0; nn < Axis->blue_count; nn++ )
+ {
+ max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
+ max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
+ }
+
+ dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
+ dist &= ~127;
+
+ if ( dist == 0 )
+ {
+ scale = new_scale;
+
+ FT_TRACE5((
+ "af_latin_metrics_scale_dim:"
+ " x height alignment (style `%s'):\n"
+ " "
+ " vertical scaling changed from %.4f to %.4f (by %d%%)\n"
+ "\n",
+ af_style_names[metrics->root.style_class->style],
+ axis->org_scale / 65536.0,
+ scale / 65536.0,
+ ( fitted - scaled ) * 100 / scaled ));
+ }
+#ifdef FT_DEBUG_LEVEL_TRACE
+ else
+ {
+ FT_TRACE5((
+ "af_latin_metrics_scale_dim:"
+ " x height alignment (style `%s'):\n"
+ " "
+ " excessive vertical scaling abandoned\n"
+ "\n",
+ af_style_names[metrics->root.style_class->style] ));
+ }
+#endif
}
}
}
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -74,6 +74,8 @@
{
AF_WidthRec ref;
AF_WidthRec shoot;
+ FT_Pos ascender;
+ FT_Pos descender;
FT_UInt flags;
} AF_LatinBlueRec, *AF_LatinBlue;