[Development] Behavioral change with font metrics

Eskil Abrahamsen Blomfeldt Eskil.Abrahamsen-Blomfeldt at qt.io
Wed May 29 10:14:22 CEST 2024


Hi,

I have a pending change which I would like to get into Qt 6.8 which will change default line heights of fonts in some cases, so I thought I would mention it here to hear if people have objections. Since it does change text layouts in some cases, it also adds a fallback mechanism to previous behavior, both per font with a style strategy in QFont and an application attribute. Some users will notice this and manually have to change their code if they are unhappy with the changes, but in practice it is a correctness fix.

https://codereview.qt-project.org/c/qt/qtbase/+/563751

Background is this:

In OpenType fonts there are three different sets of metrics providing the vertical metrics of the font

  *
The ascender/descender/lineGap in the HHEA table (predates OpenType)
  *
The winAscent/winDescent in the OS/2 table
  *
The typoAscender/typoDescender/typoLineGap also in the OS/2 table

Microsoft's approach is typically to add new fields to OpenType rather than risk breaking legacy software, so the format is kind of convoluted due to this. In most fonts the HHEA values will match the typo* values, but older implementations of the font system had platform-specific handling of these (as the spec says), so to ensure backwards-compatibility, Microsoft added the additional sets.

The winAscent/winDescent are used for clipping the glyphs, so they need to be set so that no glyph in the font is higher than winAscent+winDescent. Often the sum will match typoAscender-typoDescender+typoLineGap, but not always. The clipping requirement makes them less suitable for typography, since there's no way to add e.g. glyphs that are taller than the line height of the font. But many applications still used winAscent+winDescent for line heights, including Microsoft's own GDI. So to make it possible to keep the default of winAscent+winDescent for existing fonts but still allow fonts to expand beyond this, they later added the USE_TYPO_METRICS flag to the OS/2 table, which is supposed to be set if the typo* metrics are valid to use.

In Qt 5 we would have platform-specific handling of this:

  *
Windows would use winAscent+winDescent as default, unless USE_TYPO_METRICS was set, in which case the typo* metrics were used
  *
FreeType would use the typo* metrics if available
  *
macOS would use the original metrics in HHEA, even if the OS/2 table is present in the font, typically matching the typo* metrics.

Users were complaining about inconsistent layouts between platforms, and in Qt 6.0 we tried to consolidate, by making all platforms use the OS/2 data if available, and prefer typo* metrics if the USE_TYPO_METRICS was set and win* metrics if not.

We early found out that this was not a viable plan on macOS, because some fonts that are only used on macOS have OS/2 tables with invalid data in them. So we changed macOS to use the platform values again instead. This typically matches the typo* values granted that those are set correctly, because there is no reason for these to be different. But we kept the changed default on FreeType, so that this now matches Windows.

Some recent discussions has made me regret this decision, though. The OpenType spec<https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswinascent> very clearly states:

Some legacy applications use the usWinAscent and usWinDescent values to determine default line spacing. This is strongly discouraged. The sTypo* fields should be used for this purpose.

So despite GDI choosing the backwards compatible route, the recommendation is to always use the typo* metrics for line spacing. This means that modern font systems that are not limited by compatibility concerns will use this, and this in turn means that fonts will be designed with this in mind. Font designers will often neglect to set the USE_TYPO_METRICS flag even if the typo* metrics are preferable, because the fonts work fine on FreeType and DirectWrite applications.

Now, the conservative approach would be to do what Microsoft did and keep the current default + add an opt-in for the correct behavior. But I fear becoming a primarily compatibility-driven toolkit can be inhibiting, like it is for GDI, so I would rather like to default to correctness, following the recommendation in the spec and introduce an opt-out for those users who want to get back the original behavior.

So that's what my change currently does. By default, macOS will still use HHEA (so font designers still need to make sure those are in sync with the other metrics) but Windows and FreeType will both now prefer the typo* metrics, even if the USE_TYPO_METRICS flag is unset. If PreferLegacyLineMetrics is set, then all platforms (including macOS) will use typo* metrics if USE_TYPO_METRICS is set and win* metrics otherwise, granted that the OS/2 table exists in the font. (I think changing macOS to correspond to the others here is ok, since it's a manual opt-in.)

Some users will see that text layouts get smaller and it might mess up their UIs, especially if they were designed with hardcoded sizes. These users can easily get back previous behavior by setting the opt-out flags though, so at least there is a very fast solution. And hopefully most users will be happy that Qt is working according to the spec.

Any comments or thoughts?


--

Eskil Abrahamsen Blomfeldt

Senior Manager, Graphics Engines



The Qt Company

Sandakerveien 116

0484, Oslo, Norway

eskil.abrahamsen-blomfeldt at qt.io

+47 938 85 836

http://qt.io



The Future is Written with Qt

--


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20240529/e46057c2/attachment-0001.htm>


More information about the Development mailing list