question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Interpolating Ubuntu Mono fails with "Errors calculating 427 glyphs" due to IndexError in "fontMath/mathGlyph.py"

See original GitHub issue

Hi there,

This looks like a really cool project. I tried to get a feel of how it works by interpolating a semi-bold version of Ubuntu Mono. I used FontForge to convert the TTFs to UFO:

font = fontforge.open("UbuntuMono-R.ttf")
font.generate("UbuntuMono-R.ufo")
font.close()

Then I made the following designspace file:

<?xml version="1.0" ?>
<designspace format="3">
    <sources>
        <source filename="sources/ufos/UbuntuMono-R.ufo" name="ubuntu_mono_regular">
            <lib copy="1"/>
            <groups copy="1"/>
            <info copy="1"/>
            <location>
                <dimension name="weight" xvalue="400"/>
            </location>
        </source>
        <source filename="sources/ufos/UbuntuMono-B.ufo" name="ubuntu_mono_bold">
            <location>
                <dimension name="weight" xvalue="700"/>
            </location>
        </source>
    </sources>
    <instances>
        <instance familyname="Ubuntu Mono" filename="outputs/UbuntuMono-M.ufo" stylename="Medium">
            <location>
                <dimension name="weight" xvalue="500"/>
            </location>
            <info/>
            <kerning/>
        </instance>
        <instance familyname="Ubuntu Mono" filename="outputs/UbuntuMono-SB.ufo" stylename="SemiBold">
            <location>
                <dimension name="weight" xvalue="600"/>
            </location>
            <info/>
            <kerning/>
        </instance>
    </instances>
</designspace>

Finally, I ran MutatorMath like this:

from mutatorMath.ufo import build
build("ubuntu-mono.designspace")

Unfortunately, this failed to generate a valid font; the log says:

2016-10-25 01:05:26,775 MutatorMath Executing designspace document: ubuntu-mono.designspace
2016-10-25 01:05:26,800 MutatorMath Writing UbuntuMono-M.ufo to outputs/UbuntuMono-M.ufo
2016-10-25 01:05:27,849 MutatorMath     Multiple unicode values for glyph nonmarkingreturn: 9, 13
2016-10-25 01:05:27,850 MutatorMath     Multiple unicode values for glyph .null: 8, 0, 29
2016-10-25 01:05:29,731 MutatorMath outputs/UbuntuMono-M.ufo:
Errors calculating 427 glyphs: 
[…]

I removed the catch-all exception handler around _calculateGlyph in ufo/instance.py and got the following backtrace:

Traceback (most recent call last):
  File "./buildinstances.py", line 19, in <module>
    main()
  File "./buildinstances.py", line 16, in main
    build("ubuntu-mono.designspace")
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/__init__.py", line 56, in build
    reader.process()
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/document.py", line 418, in process
    self.readInstances(makeGlyphs=makeGlyphs, makeKerning=makeKerning, makeInfo=makeInfo)
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/document.py", line 572, in readInstances
    self._readSingleInstanceElement(instanceElement, makeGlyphs=makeGlyphs, makeKerning=makeKerning, makeInfo=makeInfo)
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/document.py", line 631, in _readSingleInstanceElement
    instanceObject.addGlyph(n, unicodeValue)
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/instance.py", line 345, in addGlyph
    self._calculateGlyph(glyphObject, instanceLocation, glyphMasters)
  File "./deps/MutatorMath/Lib/mutatorMath/ufo/instance.py", line 371, in _calculateGlyph
    bias, m = buildMutator(items, warpDict=self.warpDict)
  File "./deps/MutatorMath/Lib/mutatorMath/objects/mutator.py", line 46, in buildMutator
    onx.append((lb, obj-m.getNeutral()))
  File "./deps/fontMath/Lib/fontMath/mathGlyph.py", line 167, in __sub__
    self._processMathOne(copiedGlyph, otherGlyph, subPt, sub)
  File "./deps/fontMath/Lib/fontMath/mathGlyph.py", line 178, in _processMathOne
    copiedGlyph.contours = _processMathOneContours(self.contours, otherGlyph.contours, ptFunc)
  File "./deps/fontMath/Lib/fontMath/mathGlyph.py", line 516, in _processMathOneContours
    pt2 = points2[index][1]
IndexError: list index out of range

Here’s the context in which this error occurred, courtesy of PDB:

(Pdb) pprint(locals())
{'contour1': {'identifier': None,
              'points': [('qcurve', (249, 499), False, None, None),
                         (None, (239, 464), False, None, None),
                         (None, (222, 401), False, None, None),
                         (None, (207, 340), False, None, None),
                         (None, (194, 278), False, None, None),
                         ('qcurve', (188, 245), False, None, None),
                         (None, (188, 245), False, None, None),
                         (None, (309, 245), False, None, None),
                         ('curve', (309, 245), False, None, None),
                         (None, (303, 278), False, None, None),
                         (None, (291, 340), False, None, None),
                         (None, (276, 401), False, None, None),
                         (None, (259, 464), False, None, None)]},
 'contourIdentifier': None,
 'contours1': [{'identifier': None,
                'points': [('curve', (359, 0), False, None, None),
                           (None, (359, 0), False, None, None),
                           (None, (330, 143), False, None, None),
                           ('curve', (330, 143), False, None, None),
                           (None, (330, 143), False, None, None),
                           (None, (165, 143), False, None, None),
                           ('curve', (165, 143), False, None, None),
                           (None, (165, 143), False, None, None),
                           (None, (137, 0), False, None, None),
                           ('curve', (137, 0), False, None, None),
                           (None, (137, 0), False, None, None),
                           (None, (9, 0), False, None, None),
                           ('curve', (9, 0), False, None, None),
                           (None, (53, 183), False, None, None),
                           (None, (143, 484), False, None, None),
                           ('qcurve', (185, 619), False, None, None),
                           (None, (185, 619), False, None, None),
                           (None, (319, 619), False, None, None),
                           ('curve', (319, 619), False, None, None),
                           (None, (363, 483), False, None, None),
                           (None, (450, 178), False, None, None),
                           ('qcurve', (491, 0), False, None, None),
                           (None, (491, 0), False, None, None),
                           (None, (359, 0), False, None, None)]},
               {'identifier': None,
                'points': [('qcurve', (249, 499), False, None, None),
                           (None, (239, 464), False, None, None),
                           (None, (222, 401), False, None, None),
                           (None, (207, 340), False, None, None),
                           (None, (194, 278), False, None, None),
                           ('qcurve', (188, 245), False, None, None),
                           (None, (188, 245), False, None, None),
                           (None, (309, 245), False, None, None),
                           ('curve', (309, 245), False, None, None),
                           (None, (303, 278), False, None, None),
                           (None, (291, 340), False, None, None),
                           (None, (276, 401), False, None, None),
                           (None, (259, 464), False, None, None)]}],
 'contours2': [{'identifier': None,
                'points': [('curve', (404, 0), False, None, None),
                           (None, (404, 0), False, None, None),
                           (None, (367, 162), False, None, None),
                           ('curve', (367, 162), False, None, None),
                           (None, (367, 162), False, None, None),
                           (None, (129, 162), False, None, None),
                           ('curve', (129, 162), False, None, None),
                           (None, (129, 162), False, None, None),
                           (None, (93, 0), False, None, None),
                           ('curve', (93, 0), False, None, None),
                           (None, (93, 0), False, None, None),
                           (None, (9, 0), False, None, None),
                           ('curve', (9, 0), False, None, None),
                           (None, (26, 66), False, None, None),
                           (None, (68, 220), False, None, None),
                           (None, (117, 382), False, None, None),
                           (None, (171, 545), False, None, None),
                           ('qcurve', (201, 619), False, None, None),
                           (None, (201, 619), False, None, None),
                           (None, (303, 619), False, None, None),
                           ('curve', (303, 619), False, None, None),
                           (None, (332, 545), False, None, None),
                           (None, (385, 382), False, None, None),
                           (None, (432, 220), False, None, None),
                           (None, (474, 66), False, None, None),
                           ('qcurve', (491, 0), False, None, None),
                           (None, (491, 0), False, None, None),
                           (None, (404, 0), False, None, None)]},
               {'identifier': None,
                'points': [('qcurve', (249, 547), False, None, None),
                           (None, (226, 484), False, None, None),
                           (None, (172, 318), False, None, None),
                           ('qcurve', (148, 230), False, None, None),
                           (None, (148, 230), False, None, None),
                           (None, (348, 230), False, None, None),
                           ('curve', (348, 230), False, None, None),
                           (None, (325, 320), False, None, None),
                           (None, (272, 487), False, None, None)]}],
 'func': <function subPt at 0x7f7f3bbefc80>,
 'identifier': None,
 'index': 9,
 'name': None,
 'point': (None, (303, 278), False, None, None),
 'points1': [('qcurve', (249, 499), False, None, None),
             (None, (239, 464), False, None, None),
             (None, (222, 401), False, None, None),
             (None, (207, 340), False, None, None),
             (None, (194, 278), False, None, None),
             ('qcurve', (188, 245), False, None, None),
             (None, (188, 245), False, None, None),
             (None, (309, 245), False, None, None),
             ('curve', (309, 245), False, None, None),
             (None, (303, 278), False, None, None),
             (None, (291, 340), False, None, None),
             (None, (276, 401), False, None, None),
             (None, (259, 464), False, None, None)],
 'points2': [('qcurve', (249, 547), False, None, None),
             (None, (226, 484), False, None, None),
             (None, (172, 318), False, None, None),
             ('qcurve', (148, 230), False, None, None),
             (None, (148, 230), False, None, None),
             (None, (348, 230), False, None, None),
             ('curve', (348, 230), False, None, None),
             (None, (325, 320), False, None, None),
             (None, (272, 487), False, None, None)],
 'pprint': <function pprint at 0x7f7f3a2fc378>,
 'pt': (37, -242),
 'pt1': (303, 278),
 'pt2': (272, 487),
 'result': [{'identifier': None,
             'points': [('curve', (-45, 0), False, None, None),
                        (None, (-45, 0), False, None, None),
                        (None, (-37, -19), False, None, None),
                        ('curve', (-37, -19), False, None, None),
                        (None, (-37, -19), False, None, None),
                        (None, (36, -19), False, None, None),
                        ('curve', (36, -19), False, None, None),
                        (None, (36, -19), False, None, None),
                        (None, (44, 0), False, None, None),
                        ('curve', (44, 0), False, None, None),
                        (None, (44, 0), False, None, None),
                        (None, (0, 0), False, None, None),
                        ('curve', (0, 0), False, None, None),
                        (None, (27, 117), False, None, None),
                        (None, (75, 264), False, None, None),
                        ('qcurve', (68, 237), False, None, None),
                        (None, (14, 74), False, None, None),
                        (None, (118, 0), False, None, None),
                        ('curve', (118, 0), False, None, None),
                        (None, (60, -136), False, None, None),
                        (None, (147, -441), False, None, None),
                        ('qcurve', (159, -545), False, None, None),
                        (None, (106, -382), False, None, None),
                        (None, (-73, -220), False, None, None)]}],
 'resultPoints': [('qcurve', (0, -48), False, None, None),
                  (None, (13, -20), False, None, None),
                  (None, (50, 83), False, None, None),
                  (None, (59, 110), False, None, None),
                  (None, (46, 48), False, None, None),
                  ('qcurve', (-160, 15), False, None, None),
                  (None, (-160, 15), False, None, None),
                  (None, (-16, -75), False, None, None),
                  ('curve', (37, -242), False, None, None)],
 'segmentType': None,
 'smooth': False}

Am I doing something wrong? Thanks for this cool project!

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
typesupplycommented, Oct 25, 2016

Is there a fundamental reason for interpolation to not work on masters with different numbers of points? (IOW, is there a fundamental reason why making UFOs interpolatable can’t be done automatically?) Something like introducing points in both masters to make sure they have as many, is related locations.

It’s possible to do this, but it wasn’t a goal of fontMath back when I wrote it. My goal was to have extremely predictable interpolation. I’ve thought about adding support for forcing compatibility by inserting points + flattening to equal numbers of line segments, but I’ve never had time to write it. I’d be happy to accept a patch that implements this (as long as it is optional and off by default, to maintain existing behavior).

0reactions
cpitclaudelcommented, Oct 25, 2016

Thanks for explaining! I understand. I don’t think this is something I could figure out myself in a small amount of time, but hopefully someone will 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found