Line height info from previous message

magister's picture

Recently there was a post here that dealt with issues of line spacing (handled differently on Mac vs PC); and how to set the various values. I think it was by John Hudson in response to someone's question. I have looked at a bunch of messages but I can't find it--can anybody point me to it? It was exactly the info I need.

Thanks - David

John Hudson's picture

>Well, it's probably about time for a full length explication, so here goes. The issue is complicated, and I'll explain the complication before outlining my 'best practices' recommendation.

[Note that the descender values in the hhea table and the OS/2 sTypoDescender field are properly expressed as negative integer (presuming the descender goes below the baseline), while the OS/2 usWinDescent value is expressed as a positive integer. For the purpose of the discussion below, all values are treated as if they were positive integers, since what matters is the sum of the values.]

Apple originally spec'd the hhea table as part of the TrueType spec. This includes three values for vertical metrics (despite the fact that the full name of the table is 'Horizontal Header'):

- Ascender
- Descender
- LineGap

Together, these values determine the default linespacing in Mac applications that use system font metrics. [This is typical of word processing apps, text editors, and other apps that that do not , as a default, handle leading independently of font size. Page layout apps and other professional graphics software will typically not use the font metrics to determine linespacing, but will expect the user to set leading values or will calculate 'auto' leading as a percentage of the font size.]

When Microsoft licensed TrueType, and began the extensions of the sfnt table format that would lead eventually to OpenType, they decided to spec their own vertical metrics values in the grab-all OS/2 table. One of the reasons for this was the need to be able to create fonts that had backwards compatible metrics with existing Windows bitmap fonts. This led to the OS/2 table containing two different sets of vertical metrics data:

- sTypoAscender
- sTypoDescender
- sTypoLineGap

and

- usWinAscent
- usWinDescent

As originally intended by Microsoft, the 'Typo' values were intended to be used by apps to calculate default linespacing, in exactly the same way as the corresponding hhea table values on the Mac. The 'usWin' values were intended to define clipping zones for the font, and as such were expected to correspond to the actual vertical extremes of the tallest and deepest glyphs in a font, to ensure that these would not be clipped (i.e. have pixels chopped off on screen).

If this intent were followed, one could obtain reliable cross-platform default linespacing by making the hhea vertical metrics values equal to the corresponding OS/2 'Typo' values.

However, almost every Windows app developer -- including Microsoft's own app teams -- have incorrectly calculated default linespacing based on the OS/2 'usWin' values instead of the correct, 'Typo' values. It seems likely that this is the result of some application developers noting that using the 'usWin' values ensured that all glyphs in most fonts avoidec contact with any glyphs on lines above or below, while this was not always the case with the 'Typo' values.

So we're now in a complicated situation in which:

a) the specification clearly indicates that the correct way to produce cross-platform linespacing is to make the OS/2 'Typo' and hhea vertical metrics equivalent;

b) basically all Windows apps calculate linespacing incorrectly;

c) therefore, the only way to get reliable cross-platform linespacing is by deliberately ignoring the specification, and by making the hhea table values equivalent to the OS/2 'usWin' values.


One can sidestep the issue by making the sum of the OS/2 'Typo' and 'usWin' values equivalent, so that all three sets of values produce equivalent results. In my experience, this approach -- as outlined below -- will produce good results for most text faces and probably the majority of display faces. But display faces with abnormally long extenders can be a problem, because one must either clip the extenders or set all the values to provide clearance, which produces abnormally large linespacing. We hit this issue when we were making the AAT version of Zapfino that ships with Mac OS X.

Leaving aside the for-now unsolveable issue of such display faces, here are my recommendations for setting the OS/2 and hhea font metrics.

1. OS/2 usWin values:
These should be set to determine the default linespacing, since this is what almost all Windows apps will actually use. For most designs, this will also ensure that glyphs are not clipped, since default linespacing typically includes enough 'leading' to provide clearance. If non-clipping is vital, you simply have to ensure that these values serve double-duty. If you have no very tall or deep glyphs that you want to avoid clipping, a good basic setting for these values will equal the UPM value of the font multiplied by 1.20 or 1.25, as this is a reasonable default leading. The actual value of the two fields should reflect the design. In Latin faces this will typically mean than a larger value is assigned to the usWinAscent field, while in some Arabic fonts the values might favour the descender. For the purpose of this explanation, let's assume a Latin text face with typical TT UPM of 2048, which we'll multiply by 1.25 (=2560) and assign like this:

- usWinAscent = 1836
- usWinDescent = 724


2. Os/2 'Typo' values
We want to make the sum of these values equivalent to the usWin values, i.e. to add up to 2560. My recommendation here is to make the sum of the sTypoAscender and sTypoDescender equal to the font UPM value (2048), and to assign the different between this and 2560 to the sTypoLineGap field. Again this should correspond to the design, and you should begin by measuring your typical ascender height and descender depth, e.g. measuring the lowercase d and p. Then, if the combined height of these is shorter than 2048, add the difference in equal amounts to the sTypoAscender and sTypoDescender. So let's assume that the typical height of the ascender in our example font is 1430 and the typical descender depth is 550, i.e. a total height of 1980.

2048 - 1930 = 68 and 68 /2 = 34

So this gives us

- sTypoAscender = 1464
- sTypoDescender = 584 (actually -584)

and the difference between 2048 and the combined usWin values of 2560 gives us

- sTypoLineGap = 512


3. hhea values
Now setting the hhea values and obtaining cross-platform linespacing is easy, because you can simply make these values match the corresponding OS/2 'Typo' values:

- Ascender = 1464
- Descender = 584 (actually -584)
- LineGap = 512

aquatoad's picture

Brilliant!

John, so nice to get a sensible and technically accurate answer to
this question (with instructions no less). Thanks!

Randy

paul d hunt's picture

so what's the latest thinking on this? What are your revised "best practices," John?

paul d hunt's picture

bump. has this been sorted out?

paul d hunt's picture

anyone?

dezcom's picture

Enquiring minds want to know, as in me too :-)

ChrisL

Miguel Sousa's picture

BTW, there's a wiki page over here: Vertical Metrics How-To

paul d hunt's picture

yes, miguel. i made that page. :^P. but at the bottom, John says he would report back after ATypI to get us up to date with the latest thinking on the subject. Anyone heard from John?

Syndicate content Syndicate content