Variable font instance widths don't match FC_WIDTH_* integer constants
For reference, I'm using the file Inconsolata[wdth,wght].ttf
retrieved from this commit.
I've been seeing a problem with this font when used with Pango, where some of the width instances are not named correctly by Pango - in particular, the "ExtraCondensed" and "SemiExpanded" instances lose their width names.
So, looking into the issue, I see when loading the font (with FC_DEBUG=256),
found family (n 1 p 3 e 1 l 0x0409)Inconsolata
found style (n 268 p 3 e 1 l 0x0409) ExtraCondensed Regular
found style (n 268 p 1 e 0 l 0x0000) ExtraCondensed Regular
os2 weight class 400 multiplier 1 maps to weight 80
os2 width class 5 multiplier 0.625 maps to width 62.5
complex_ features in this font: otlayout:DFLT otlayout:latn
Style ExtraCondensed Regular maps to slant -1
Style ExtraCondensed Regular maps to decorative 0
found family (n 1 p 3 e 1 l 0x0409)Inconsolata
found style (n 284 p 3 e 1 l 0x0409) SemiCondensed Regular
found style (n 284 p 1 e 0 l 0x0000) SemiCondensed Regular
os2 weight class 400 multiplier 1 maps to weight 80
os2 width class 5 multiplier 0.875 maps to width 87.5
complex_ features in this font: otlayout:DFLT otlayout:latn
Style SemiCondensed Regular maps to slant -1
Style SemiCondensed Regular maps to decorative 0
found family (n 1 p 3 e 1 l 0x0409)Inconsolata
found style (n 300 p 3 e 1 l 0x0409) SemiExpanded Regular
found style (n 300 p 1 e 0 l 0x0000) SemiExpanded Regular
os2 weight class 400 multiplier 1 maps to weight 80
os2 width class 5 multiplier 1.125 maps to width 112.5
complex_ features in this font: otlayout:DFLT otlayout:latn
Style SemiExpanded Regular maps to slant -1
Style SemiExpanded Regular maps to decorative 0
Fontconfig is calculating floating point widths, which are correct as far as the os2 usWidthClass values go.
However, Pango retrieves these values using FcPatternGetInteger ()
in order to compare with the FC_WIDTH_*
constants from fontconfig.h
, notably:
#define FC_WIDTH_EXTRACONDENSED 63
#define FC_WIDTH_SEMICONDENSED 87
#define FC_WIDTH_SEMIEXPANDED 113
But since the width is being stored as a floating point value, the FcPatternGetInteger ()
function truncates the numbers, resulting in:
Width | FC_WIDTH_OBJECT |
FcPatternGetInteger |
FC_WIDTH_* constant |
---|---|---|---|
Ultra-condensed | 50.0 | 50 | 50 |
Extra-condensed | 62.5 | 62 | 63 |
Condensed | 75.0 | 75 | 75 |
Semi-condensed | 87.5 | 87 | 87 |
Normal | 100.0 | 100 | 100 |
Semi-expanded | 112.5 | 112 | 113 |
Expanded | 125.0 | 125 | 125 |
Extra-expanded | 150.0 | 150 | 150 |
Ultra-expanded | 200.0 | 200 | 200 |
So, there's an oddity here. You might think that having the FcPatternGetInteger ()
function round the value instead of truncate it would work, but that would actually break the Semi-condensed instance, since for some reason 87.5 got rounded down to 87 instead of up to 88 in the integer constant.
Pango could switch to retrieving the floating point values, but then non-variable fonts would cause problems, because the widths for those are set to the integer constants rather than the floating point values. I suppose it could check a range of values when attempting to figure out the name from the width…
Any thoughts?