[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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
diff --git a/ChangeLog b/ChangeLog
index cc8ba89..28cec3e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2015-11-06 Philipp Knechtges <philipp-dev@knechtges.com>
+
+ [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 <wl@gnu.org>
[sfnt] Ignore embedded bitmaps with zero size (#46379).
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index 5645aaf..53851e7 100644
--- 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_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 ));
+ FT_Pos max_height;
+ FT_Pos dist;
+ FT_Fixed new_scale;
+
+
+ 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
}
}
}
diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h
index 6855492..dd75ef3 100644
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -74,6 +74,8 @@ FT_BEGIN_HEADER
{
AF_WidthRec ref;
AF_WidthRec shoot;
+ FT_Pos ascender;
+ FT_Pos descender;
FT_UInt flags;
} AF_LatinBlueRec, *AF_LatinBlue;