Incorrect LSBs for VF Composite Glyphs

Hi!

We found that PDFs exported from CoreText apps like Pages render incorrectly in Adobe apps when a variable font contains composite glyphs.

Probably, this happens because macOS doesn’t recalculate LSB values when embedding an instance of the VF. An example with coretext-view and fonttools:

coretext-view --variations "wdth=0" LSBTestVF.ttf "i" && mutool extract out.pdf  | sed -n 's/^extracting //p' | xargs ttx -q -t hmtx -t glyf -o - | grep '\"i\"'

    <mtx name="i" width="160" lsb="32"/> // <---- Should be 13
    <TTGlyph name="i" xMin="13" yMin="0" xMax="147" yMax="732">

But macOS preinstalled fonts work fine because they use USE_MY_METRICS flag on base componets:

ttx /System/Library/Fonts/SFNS.ttf -t glyf -o - | grep "\"Aacute\"" -A 5

   <TTGlyph name="Aacute" xMin="25" yMin="0" xMax="1276" yMax="1848">
      <component glyphName="A" x="0" y="0" flags="0x204"/>  // <---- USE_MY_METRICS
      <component glyphName="acutecmb.short" x="651" y="403" flags="0x4"/>
    </TTGlyph>

What is the best way to export a VF in this case, other than using Decompose Glyphs in the Custom parameters?

Thank you.

testfont.glyphs (3.6 KB)

3.5 (3526)

Can you try to add that flag with ttx and confirm that it fixes this?

Sure. I’ve tested it and adding the flag to a ttx fixed the issue.

A follow up. ufo2ft has a heuristic that sets the USE_MY_METRICS using the following code, so building with fonttools works fine:

def autoUseMyMetrics(self, ttGlyph, glyphName):
    """Set the "USE_MY_METRICS" flag on the first component having the
    same advance width as the composite glyph, no transform and no
    horizontal shift (but allow it to shift vertically).
    This forces the composite glyph to use the possibly hinted horizontal
    metrics of the sub-glyph, instead of those from the "hmtx" table.
    """
    hmtx = self.otf["hmtx"]
    width = hmtx[glyphName][0]
    for component in ttGlyph.components:
        try:
            baseName, transform = component.getComponentInfo()
        except AttributeError:
            # component uses '{first,second}Pt' instead of 'x' and 'y'
            continue
        try:
            baseMetrics = hmtx[baseName]
        except KeyError:
            continue  # ignore missing components
        else:
            if baseMetrics[0] == width and transform[:-1] == (1, 0, 0, 1, 0):
                component.flags |= USE_MY_METRICS
                break

Interesting. I’ll have a look at this.

1 Like