[truetype] Improve emulation of vertical metrics. This commit also improves the start values of vertical phantom points. Kudos to Greg Hitchcock for help. * src/truetype/ttgload.c (TT_Get_VMetrics): Add parameter to pass `yMax' value. Replace code with fixed Microsoft definition. (tt_get_metrics): Updated. (TT_LOADER_SET_PP): Add explanation how to initialize phantom points, taken from both the OpenType specification and private communication with Greg (which will eventually be added to the standard). Fix horizontal position of `pp3' and `pp4'. * src/truetype/ttgload.h: Updated. * src/truetype/ttdriver.c (tt_get_advances): Updated. * docs/CHANGES: Updated.
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
diff --git a/ChangeLog b/ChangeLog
index c44b3f9..115333d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2013-11-06 Werner Lemberg <wl@gnu.org>
+
+ [truetype] Improve emulation of vertical metrics.
+
+ This commit also improves the start values of vertical phantom
+ points. Kudos to Greg Hitchcock for help.
+
+ * src/truetype/ttgload.c (TT_Get_VMetrics): Add parameter to pass
+ `yMax' value. Replace code with fixed Microsoft definition.
+ (tt_get_metrics): Updated.
+ (TT_LOADER_SET_PP): Add explanation how to initialize phantom
+ points, taken from both the OpenType specification and private
+ communication with Greg (which will eventually be added to the
+ standard).
+ Fix horizontal position of `pp3' and `pp4'.
+
+ * src/truetype/ttgload.h: Updated.
+
+ * src/truetype/ttdriver.c (tt_get_advances): Updated.
+
+ * docs/CHANGES: Updated.
+
2013-11-05 Werner Lemberg <wl@gnu.org>
* builds/windows/vc2010/freetype.vcxproj: s/v110/v100/.
diff --git a/docs/CHANGES b/docs/CHANGES
index ddd24e0..c843046 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -11,6 +11,10 @@ CHANGES BETWEEN 2.5 and 2.5.1
- Many fields of the `PCLT' table in SFNT based fonts (if accessed
with `FT_Get_Sfnt_Table') were computed incorrectly.
+ - In TrueType fonts, hinting of composite glyphs could sometimes
+ deliver incorrect positions of components or even distorted
+ shapes.
+
II. IMPORTANT CHANGES
@@ -76,6 +80,12 @@ CHANGES BETWEEN 2.5 and 2.5.1
to set selector bit 6 to get results for selector bits 7-10,
which is wrong.
+ - Improved computation of emulated vertical metrics for TrueType
+ fonts.
+
+ - Fixed horizontal start-up position of vertical phantom points in
+ TrueType bytecode.
+
======================================================================
diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c
index fb25706..36d23a2 100644
--- a/src/truetype/ttdriver.c
+++ b/src/truetype/ttdriver.c
@@ -215,7 +215,8 @@
FT_UShort ah;
- TT_Get_VMetrics( face, start + nn, &tsb, &ah );
+ /* since we don't need `tsb', we use zero for `yMax' parameter */
+ TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah );
advances[nn] = ah;
}
}
diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c
index 0fc3492..0c3c7bd 100644
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -85,45 +85,30 @@
/*************************************************************************/
/* */
/* Return the vertical metrics in font units for a given glyph. */
- /* Greg Hitchcock from Microsoft told us that if there were no `vmtx' */
- /* table, typoAscender/Descender from the `OS/2' table would be used */
- /* instead, and if there were no `OS/2' table, use ascender/descender */
- /* from the `hhea' table. But that is not what Microsoft's rasterizer */
- /* apparently does: It uses the ppem value as the advance height, and */
- /* sets the top side bearing to be zero. */
+ /* See macro `TT_LOADER_SET_PP' below for explanations. */
/* */
FT_LOCAL_DEF( void )
TT_Get_VMetrics( TT_Face face,
FT_UInt idx,
+ FT_Pos yMax,
FT_Short* tsb,
FT_UShort* ah )
{
if ( face->vertical_info )
( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah );
-#if 1 /* Empirically determined, at variance with what MS said */
-
- else
- {
- *tsb = 0;
- *ah = face->root.units_per_EM;
- }
-
-#else /* This is what MS said to do. It isn't what they do, however. */
-
else if ( face->os2.version != 0xFFFFU )
{
- *tsb = face->os2.sTypoAscender;
+ *tsb = face->os2.sTypoAscender - yMax;
*ah = face->os2.sTypoAscender - face->os2.sTypoDescender;
}
+
else
{
- *tsb = face->horizontal.Ascender;
+ *tsb = face->horizontal.Ascender - yMax;
*ah = face->horizontal.Ascender - face->horizontal.Descender;
}
-#endif
-
FT_TRACE5(( " advance height (font units): %d\n", *ah ));
FT_TRACE5(( " top side bearing (font units): %d\n", *tsb ));
}
@@ -146,6 +131,7 @@
&left_bearing,
&advance_width );
TT_Get_VMetrics( face, glyph_index,
+ loader->bbox.yMax,
&top_bearing,
&advance_height );
@@ -1263,18 +1249,78 @@
}
- /* Calculate the four phantom points. */
- /* The first two stand for horizontal origin and advance. */
- /* The last two stand for vertical advance and origin. */
+ /*
+ * Calculate the phantom points
+ *
+ * Defining the right side bearing (rsb) as
+ *
+ * rsb = aw - (lsb + xmax - xmin)
+ *
+ * (with `aw' the advance width, `lsb' the left side bearing, and `xmin'
+ * and `xmax' the glyph's minimum and maximum x value), the OpenType
+ * specification defines the initial position of horizontal phantom points
+ * as
+ *
+ * pp1 = (xmin - lsb, 0) ,
+ * pp2 = (pp1 + aw, 0) .
+ *
+ * However, the specification lacks the precise definition of vertical
+ * phantom points. Greg Hitchcock provided the following explanation.
+ *
+ * - a `vmtx' table is present
+ *
+ * For any glyph, the minimum and maximum y values (`ymin' and `ymax')
+ * are given in the `glyf' table, the top side bearing (tsb) and advance
+ * height (ah) are given in the `vmtx' table. The bottom side bearing
+ * (bsb) is then calculated as
+ *
+ * bsb = ah - (tsb + ymax - ymin) ,
+ *
+ * and the initial position of vertical phantom points is
+ *
+ * pp3 = (x, ymax + tsb) ,
+ * pp4 = (x, pp3 - ah) .
+ *
+ * See below for value `x'.
+ *
+ * - no `vmtx' table in the font
+ *
+ * If there is an `OS/2' table, we set
+ *
+ * DefaultAscender = sTypoAscender ,
+ * DefaultDescender = sTypoDescender ,
+ *
+ * otherwise we use data from the `hhea' table:
+ *
+ * DefaultAscender = Ascender ,
+ * DefaultDescender = Descender .
+ *
+ * With these two variables we can now set
+ *
+ * ah = DefaultAscender - sDefaultDescender ,
+ * tsb = DefaultAscender - yMax ,
+ *
+ * and proceed as if a `vmtx' table was present.
+ *
+ * Usually we have
+ *
+ * x = aw / 2 ,
+ *
+ * but there is a compatibility case where it can be set to
+ *
+ * x = -DefaultDescender -
+ * ((DefaultAscender - DefaultDescender - aw) / 2) .
+ *
+ */
#define TT_LOADER_SET_PP( loader ) \
do { \
(loader)->pp1.x = (loader)->bbox.xMin - (loader)->left_bearing; \
(loader)->pp1.y = 0; \
(loader)->pp2.x = (loader)->pp1.x + (loader)->advance; \
(loader)->pp2.y = 0; \
- (loader)->pp3.x = 0; \
- (loader)->pp3.y = (loader)->top_bearing + (loader)->bbox.yMax; \
- (loader)->pp4.x = 0; \
+ (loader)->pp3.x = (loader)->advance / 2; \
+ (loader)->pp3.y = (loader)->bbox.yMax + (loader)->top_bearing; \
+ (loader)->pp4.x = (loader)->advance / 2; \
(loader)->pp4.y = (loader)->pp3.y - (loader)->vadvance; \
} while ( 0 )
diff --git a/src/truetype/ttgload.h b/src/truetype/ttgload.h
index 05f7588..3f1699e 100644
--- a/src/truetype/ttgload.h
+++ b/src/truetype/ttgload.h
@@ -43,6 +43,7 @@ FT_BEGIN_HEADER
FT_LOCAL( void )
TT_Get_VMetrics( TT_Face face,
FT_UInt idx,
+ FT_Pos yMax,
FT_Short* tsb,
FT_UShort* ah );