ref: 7e4b0fbfdd1e15780ff1899bb442f70ffc83791b
parent: b1d97810c95ea7a46cc27783ab0a6b2c9f812321
author: Werner Lemberg <[email protected]>
date: Wed Nov 6 02:14:49 EST 2013
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2013-11-06 Werner Lemberg <[email protected]>
+
+ [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 <[email protected]>
* builds/windows/vc2010/freetype.vcxproj: s/v110/v100/.
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -11,7 +11,11 @@
- 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
- WOFF font format support has been added.
@@ -75,6 +79,12 @@
used to retrieve subpixel hinting information. It was necessary
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.
======================================================================
--- 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;
}
}
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -85,16 +85,12 @@
/*************************************************************************/
/* */
/* 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 )
{
@@ -101,29 +97,18 @@
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,9 +1249,69 @@
}
- /* 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; \
@@ -1272,9 +1318,9 @@
(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 )
--- a/src/truetype/ttgload.h
+++ b/src/truetype/ttgload.h
@@ -43,6 +43,7 @@
FT_LOCAL( void )
TT_Get_VMetrics( TT_Face face,
FT_UInt idx,
+ FT_Pos yMax,
FT_Short* tsb,
FT_UShort* ah );