From 7e4b0fbfdd1e15780ff1899bb442f70ffc83791b Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Wed, 6 Nov 2013 07:14:49 +0100 Subject: [PATCH] [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. --- ChangeLog | 22 +++++++++ docs/CHANGES | 10 +++++ src/truetype/ttdriver.c | 3 +- src/truetype/ttgload.c | 98 ++++++++++++++++++++++++++++++----------- src/truetype/ttgload.h | 1 + 5 files changed, 107 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index c44b3f903..115333dbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2013-11-06 Werner Lemberg + + [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 * builds/windows/vc2010/freetype.vcxproj: s/v110/v100/. diff --git a/docs/CHANGES b/docs/CHANGES index ddd24e027..c8430460c 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 fb25706ab..36d23a282 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 0fc349234..0c3c7bdaf 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 05f75882d..3f1699e68 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 );