[sfnt] Use typo metrics if OS/2 fsSelection USE_TYPO_METRICS bit is set.

If the OS/2 table exists and fsSelection bit 7 (USE_TYPO_METRICS) is set,
use the sTypo* set of values to compute the FT_Face's ascender, descender
and height. Otherwise, fall back to old behavior.

* src/sfnt/sfobjs.c (sfnt_load_face): Implement.
This commit is contained in:
Nikolaus Waxweiler 2019-02-02 15:45:31 +00:00
parent f686ad46a3
commit f72b00746c
2 changed files with 74 additions and 50 deletions

View File

@ -1,3 +1,13 @@
2019-02-02 Nikolaus Waxweiler <madigens@gmail.com>
[sfnt] Use typo metrics if OS/2 fsSelection USE_TYPO_METRICS bit is set.
If the OS/2 table exists and fsSelection bit 7 (USE_TYPO_METRICS) is set,
use the sTypo* set of values to compute the FT_Face's ascender, descender
and height. Otherwise, fall back to old behavior.
* src/sfnt/sfobjs.c (sfnt_load_face): Implement.
2019-01-18 John Tytgat <John.Tytgat@esko.com>
[sfnt] Handle TT fonts having two PostScript font names (#55471).
@ -420,7 +430,7 @@
* src/base/ftobjs.c (ft_glyphslot_preset_bimap): Another tweak.
This one should be clearer. When the rounded monochrome bbox collapses
we add a pixel that covers most if not all original cbox.
we add a pixel that covers most if not all original cbox.
2018-09-21 Alexei Podtelezhnikov <apodtele@gmail.com>

View File

@ -1641,59 +1641,73 @@
root->units_per_EM = face->header.Units_Per_EM;
/* XXX: Computing the ascender/descender/height is very different */
/* from what the specification tells you. Apparently, we */
/* must be careful because */
/* */
/* - not all fonts have an OS/2 table; in this case, we take */
/* the values in the horizontal header. However, these */
/* values very often are not reliable. */
/* */
/* - otherwise, the correct typographic values are in the */
/* sTypoAscender, sTypoDescender & sTypoLineGap fields. */
/* */
/* However, certain fonts have these fields set to 0. */
/* Rather, they have usWinAscent & usWinDescent correctly */
/* set (but with different values). */
/* */
/* As an example, Arial Narrow is implemented through four */
/* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
/* */
/* Strangely, all fonts have the same values in their */
/* sTypoXXX fields, except ARIALNB which sets them to 0. */
/* */
/* On the other hand, they all have different */
/* usWinAscent/Descent values -- as a conclusion, the OS/2 */
/* table cannot be used to compute the text height reliably! */
/* */
/*
* Computing the ascender/descender/height is tricky.
*
* The OpenType specification v1.8.3 says:
*
* [OS/2's] sTypoAscender, sTypoDescender and sTypoLineGap fields
* are intended to allow applications to lay out documents in a
* typographically-correct and portable fashion.
*
* This is somewhat at odds with the decades of backwards
* compatibility, operating systems and applications doing whatever
* they want, not to mention broken fonts.
*
* Not all fonts have an OS/2 table; in this case, we take the values
* in the horizontal header, although there is nothing stopping the
* values from being unreliable. Even with a OS/2 table, certain fonts
* set the sTypoAscender, sTypoDescender and sTypoLineGap fields to 0
* and instead correctly set usWinAscent and usWinDescent.
*
* As an example, Arial Narrow is shipped as four files ARIALN.TTF,
* ARIALNI.TTF, ARIALNB.TTF and ARIALNBI.TTF. Strangely, all fonts have
* the same values in their sTypo* fields, except ARIALNB.ttf which
* sets them to 0. All of them have different usWinAscent/Descent
* values. The OS/2 table therefore cannot be trusted for computing the
* text height reliably.
*
* As a compromise, do the following:
*
* 1. If the OS/2 table exists and the fsSelection bit 7 is set
* (USE_TYPO_METRICS), trust the font and use the sTypo* metrics.
* 2. Otherwise, use the `hhea' table's metrics.
* 3. If they are zero and the OS/2 table exists,
* 1. use the OS/2 table's sTypo* metrics if they are non-zero.
* 2. Otherwise, use the OS/2 table's usWin* metrics.
*/
/* The ascender and descender are taken from the `hhea' table. */
/* If zero, they are taken from the `OS/2' table. */
root->ascender = face->horizontal.Ascender;
root->descender = face->horizontal.Descender;
root->height = root->ascender - root->descender +
face->horizontal.Line_Gap;
if ( !( root->ascender || root->descender ) )
if ( face->os2.version != 0xFFFFU && face->os2.fsSelection & 128 )
{
if ( face->os2.version != 0xFFFFU )
root->ascender = face->os2.sTypoAscender;
root->descender = face->os2.sTypoDescender;
root->height = root->ascender - root->descender +
face->os2.sTypoLineGap;
}
else
{
root->ascender = face->horizontal.Ascender;
root->descender = face->horizontal.Descender;
root->height = root->ascender - root->descender +
face->horizontal.Line_Gap;
if ( !( root->ascender || root->descender ) )
{
if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
if ( face->os2.version != 0xFFFFU )
{
root->ascender = face->os2.sTypoAscender;
root->descender = face->os2.sTypoDescender;
root->height = root->ascender - root->descender +
face->os2.sTypoLineGap;
}
else
{
root->ascender = (FT_Short)face->os2.usWinAscent;
root->descender = -(FT_Short)face->os2.usWinDescent;
root->height = root->ascender - root->descender;
if ( face->os2.sTypoAscender || face->os2.sTypoDescender )
{
root->ascender = face->os2.sTypoAscender;
root->descender = face->os2.sTypoDescender;
root->height = root->ascender - root->descender +
face->os2.sTypoLineGap;
}
else
{
root->ascender = (FT_Short)face->os2.usWinAscent;
root->descender = -(FT_Short)face->os2.usWinDescent;
root->height = root->ascender - root->descender;
}
}
}
}