googlefonts/gftools

[builder] Ensure space to be gid 1 for COLR fonts

yanone opened this issue · 18 comments

COLRv0 fonts render badly on Edge in Windows 10. The issue disappeared in Windows 11.

The browser appears to be inserting whichever glyph is on GID 1 in places such as colored glyphs, spaces, and also seemingly at random. While the screenshot below shows Arabic, the issue appears identically for Latin text.

The OpenType 1.7 Specs suggests the NULL glyph to be on GID 1, with the additional recommendation "Glyph 1 should have no contours and zero advance width".
However, this section disappeared from the OpenType 1.8 Specs and the issue is therefore to be considered a shaping bug in Windows 10.

I’m creating this issue because I believe that the space character should be put on GID 1 by gftools builder (whenever a COLR table is present) as a workaround, as I consider this to be knowledge that a font engineer (or worse, a type designer) shouldn't need to know, and can be fixed programmatically.

(The fact that it got fixed in Windows 11 suggests that Microsoft knows about the bug and won’t bother fixing it for Windows 10 users).

For reference, nanoemoji already knows about this and will put space on GID 1 when assembling a font from scratch from SVGs, but maximum_color won’t fix the order and @anthrotype said he’d like to keep it that way and have maximum_color only work on the color tables.

Also, I will reference this issue from the fontbakery check that I'm about to write.

Bildschirmfoto 2022-09-20 um 12 57 51

Bildschirmfoto 2022-09-20 um 13 12 42

on Edge in Windows 10.

i believe also on Chrome, not just Edge, on Windows 10, at least according to the above mentioned comment in nanoemoji code that says "Win 10 Chrome likes a blank gid1 so make gid1 space" (haven't actually tested this)

I think nanoemoji used to add an actual ".null" glyph with no contours and zero advances to appease Win10 initially, but then we figured that since we already were adding a glyph without contours (space), it may as well be placed as the second glyph (gid1) in the font and that did the trick.

Wouldn't it be more beneficial to move this more upstream to say fontmake?

I don't know, the bug only affects COLRv0 fonts on Windows 10. Are you saying fontmake should move space glyph to gid1 all the time? The only requirement we make is that .notdef is the first glyph (otherwise cmap gets screwed), and we add one at gid0 if missing from the source.
How would we identify the "space" glyph. Can't simply rely on the name, that can be anything. I guess one would have to search the glyphs for one that's mapped to 0x0020 and has no contours. Note that space is not a required glyph either (never mind the legacy spec recommendations). The Win10 rendering bug would be worked around by placing any zero-contour glyph to gid1 (not necessarily "space" 0x0020). But there's also the possibility that the font source contains no zero-contour glyph, in which case you'd have to create one just for this.

i think general purpose tools like fontmake or maximum_color just do just what they are told, whereas more opinionated ones like gftools builder can choose to enforce that space be present and is at glyph index 1 whenever the output is COLR font and justify that with a bug affecting a major implementation.

Are you saying fontmake should move space glyph to gid1 all the time?

Just if we're dealing with a colr v0 font.

How would we identify the "space" glyph.

Something like

if `0x20` in cmap and noContours:
    # move to gid1
else:
    # make blank glyph

One could argue that we're trying to work around software bugs here. Perhaps we should submit a bug to MS since they're still supporting Win 10 till ~2025.

I don't mind rolling a temp fix in the gftools builder and mailing MS so this gets fixed completely.

They fixed it in Windows 11 and didn't bother for Windows 10...

unlikely that they'll backport that fix.

Also, to know that the output is going to be a COLR v0 and not a COLR v1 font, ufo2ft would have to build the COLR table first and check what the resulting version coming off fontTools.colorLib actually is..

Another reason to move this upstream is that some folks do not use our builder. What about a ufo filter?

What about a ufo filter?

no, that gets too complicated. Would you like to work on a PR for ufo2ft?

I don't mind hurting myself on this. I'll probably opt for the easier option after attempting it ;-).

no need to get hurt! 😄
I agree that it'd be better if COLRv0 built with ufo2ft would just work on windows 10, which is still used widely.
I can help you find a suitable place inside ufo2ft codebase for this workaround. Please file an issue over there as well thanks!

although.. I am a bit wary that having ufo2ft shuffle glyphs around and not respect the explicit UFO public.glyphOrder because some windows bug may not be the right way to go about this. E.g. what if one sets public.glyphOrder and then expects that glyphs are sorted that way in the final font (some other tool may be relying on those explicit glyph indeces for whatever reason) but then ufo2ft decides to unilaterally change it because of that windows bug..
I think I'd be comfortable with having ufo2ft emit a warning message if the second glyph is not empty and the COLR table built is version 0, so the font developer can address that in the source and set the glyphOrder accordingly.

So to summarize, I suggest that ufo2ft does the following:

  1. if UFO has no explicit glyphOrder, then place an empty glyph after .notdef and the rest sort alphabetically; we can safely do that for all the fonts, not just COLRv0. If they don't set an explicit glyphOrder, then we can assume they don't care about it and we can order them as we please
  2. if UFO has an explicit glyphOrder and we produced a COLRv0, emit a warning so the font dev can update their explicit glyphOrder accordingly, iff they care about windows 10, which we can't always guarantee is the case.

Whilst having lunch I realised that inserting a blank glyph may affect vtt hint transfers since VTT relies on glyph index order. I may just add something to the gftools.fix module for the time being.

FWIW, the spec update was in response to MicrosoftDocs/typography-issues#346.

@khaledhosny ah! Thanks Khaled, I knew I had seen this before and could not find that thread

Closing since #610 should fix this issue automatically.