Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[makeotf] winAscent/winDescent calculation seems to be based on .notdef #1479

Open
frankrolf opened this issue Mar 8, 2022 · 3 comments
Open

Comments

@frankrolf
Copy link
Member

I’ve wondered about makeotf’s complaint WARNING: Negative internal leading: win.ascent + win.descent < unitsPerEm for a while, and decided to conduct some investigation.

Setting aside the fact that winAscent and winDescent often are set equivalent to TypoAscender/TypoDescender today, I noticed that makeotf complains in almost every case, unless the values are explicitly set using a OS/2 table override.

Attached is a little script, which writes a dummy UFO, draws a glyph with given ascender and descender, and makes an OTF.
The bounds of the drawn glyph are printed, the OTF’s OS/2 table is read via ttx, and found winAscender/winDescender values are displayed.

scenario

default output (drawing into .notdef):

python3 winAscentDescentTest.py
┌──────────┐
│ 750/-250 │
└──────────┘
.notdef (0, -250, 500, 750)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌────────┐
│ 10/-10 │
└────────┘
.notdef (0, -10, 500, 10)
<usWinAscent value="10"/>
<usWinDescent value="10"/>

┌──────────┐
│ 100/-100 │
└──────────┘
.notdef (0, -100, 500, 100)
<usWinAscent value="100"/>
<usWinDescent value="100"/>

┌─────────┐
│ 250/500 │
└─────────┘
.notdef (0, 250, 500, 500)
<usWinAscent value="500"/>
<usWinDescent value="0"/>

┌──────────┐
│ 500/-250 │
└──────────┘
.notdef (0, -250, 500, 500)
<usWinAscent value="500"/>
<usWinDescent value="250"/>

┌────────┐
│ 1000/0 │
└────────┘
.notdef (0, 0, 500, 1000)
<usWinAscent value="1000"/>
<usWinDescent value="0"/>

This seems to indicate that the glyph we’re drawing is setting the winAscent/winDescent values.


alternate output (drawing into a):

python3 winAscentDescentTest.py -g a
┌──────────┐
│ 750/-250 │
└──────────┘
a (0, -250, 500, 750)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

┌────────┐
│ 10/-10 │
└────────┘
a (0, -10, 500, 10)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

┌──────────┐
│ 100/-100 │
└──────────┘
a (0, -100, 500, 100)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

┌─────────┐
│ 250/500 │
└─────────┘
a (0, 250, 500, 500)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

┌──────────┐
│ 500/-250 │
└──────────┘
a (0, -250, 500, 500)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

┌────────┐
│ 1000/0 │
└────────┘
a (0, 0, 500, 1000)
<usWinAscent value="700"/>
<usWinDescent value="0"/>

This contradicts the above assumption – all fonts have the same WinAscent value (= bounds of the default .notdef)


with features.fea present:

table OS/2 {
	winAscent 750;
	winDescent 250;
} OS/2;
┌──────────┐
│ 750/-250 │
└──────────┘
.notdef (0, -250, 500, 750)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌────────┐
│ 10/-10 │
└────────┘
.notdef (0, -10, 500, 10)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌──────────┐
│ 100/-100 │
└──────────┘
.notdef (0, -100, 500, 100)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌─────────┐
│ 250/500 │
└─────────┘
.notdef (0, 250, 500, 500)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌──────────┐
│ 500/-250 │
└──────────┘
.notdef (0, -250, 500, 500)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

┌────────┐
│ 1000/0 │
└────────┘
.notdef (0, 0, 500, 1000)
<usWinAscent value="750"/>
<usWinDescent value="250"/>

As expected, all fonts have the winAscent/winDescent set in the table override.

conclusion

  • .notdef is always used for the calculation of the winAscent/winDescent values in the font binary
  • makeotf will always emit the above complaint, unless a feature override is set, which stipulates that |winAscent| + |winDescent| == UPM
  • changing winAscent/winDescent within the UFO does not make a difference

questions

  • should the winAscent/winDescent be read from the UFO’s footprint (f.bounds)? (recommendation: maybe)
  • should the winAscent/winDescent values be read if explicitly specified in the fontinfo.plist? (recommendation: definitely)
  • should the winAscent/winDescent values fall back to the vertical metrics in fontinfo.plist? (recommendation: yes, better than relying on the bounds of .notdef)
  • should makeotf even warn about the winAscent/winDescent values, given that vertical metrics are open for interpretation? (open for discussion)

winAscentDescentTest.py.zip

@josh-hadley
Copy link
Collaborator

Interesting results 😸

I agree with your recommendations. But if we are going to make changes to makeotf's behavior we will need to be careful to advertise it, as it's possible some users might be relying on the current behavior (even unknowingly) and an unexpected change could cause headaches. Triggering the new behavior with a new flag could avoid that, but then that's yet another flag to document and maintain.

@frankrolf
Copy link
Member Author

Probably the strongest point is that many values within the UFO are simply ignored by makeotf (also seen in #1470, for example). If the respective values are set, I think they should be used.

@ryanbugden
Copy link

Agree that .notdef shouldn't have any bearing on how winAscent and winDescent are set. I think any unknowing reliance on the current behavior is kind of on the user

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants