simoncozens/babelfont

Same classDef issue, but now as result of unparse()

yanone opened this issue · 5 comments

yanone commented

I found another one, but now in another package:

In [1]: import babelfont

In [2]: font = babelfont.load("ofl/carlito/Carlito-Regular.ttf")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[2], line 1
----> 1 font = babelfont.load("ofl/carlito/Carlito-Regular.ttf")

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/babelfont/__init__.py:17, in load(filename)
     16 def load(filename):
---> 17     return Convert(filename).load()

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/babelfont/convertors/__init__.py:70, in Convert.load(self, **kwargs)
     68 for c in self.convertors:
     69     if c.can_load(self, **kwargs):
---> 70         return c.load(self, **kwargs)
     71 raise NotImplementedError

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/babelfont/convertors/__init__.py:26, in BaseConvertor.load(cls, convertor)
     24 self.filename = convertor.filename
     25 self.scratch = convertor.scratch
---> 26 return self._load()

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/babelfont/convertors/truetype.py:48, in TrueType._load(self)
     46 self._load_names()
     47 self._load_glyphs()
---> 48 self._load_features()
     49 return self.font

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/babelfont/convertors/truetype.py:342, in TrueType._load_features(self)
    341 def _load_features(self):
--> 342     self.font.features = unparse(self.tt)
    343     # Load anchors
    344     for routine in self.font.features.routines:

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/__init__.py:63, in unparse(font, do_gdef, doLookups, config)
     58 languageSystems = unparseLanguageSystems(gsub_gpos)
     60 if "GSUB" in font:
     61     GSUBUnparser(
     62         font["GSUB"], ff, languageSystems, font=font, config=config
---> 63     ).unparse(doLookups=doLookups)
     65 if "GPOS" in font:
     66     GPOSUnparser(
     67         font["GPOS"], ff, languageSystems, font=font, config=config
     68     ).unparse(doLookups=doLookups)

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/GTableUnparser.py:98, in GTableUnparser.unparse(self, doLookups)
     96 if not self.table.ScriptList:
     97     return
---> 98 self.unparseLookups()
     99 self.collectFeatures()
    100 self.fontFeatures.resolveAllRoutines()

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/GTableUnparser.py:191, in GTableUnparser.unparseLookups(self)
    188     self.fontFeatures.routines.append(r)
    190 for lookupIdx, lookup in enumerate(self.table.LookupList.Lookup):
--> 191     routine, deps = self.unparseLookup(lookup, lookupIdx)
    192     debug = self.getDebugInfo(self._table, lookupIdx)
    193     if debug:

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/GTableUnparser.py:216, in GTableUnparser.unparseLookup(self, lookup, lookupIdx)
    214 self.currentLookup = lookupIdx
    215 unparser = getattr(self, "unparse" + self.lookupTypes[lookup.LookupType])
--> 216 return unparser(lookup)

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/GSUBUnparser.py:144, in GSUBUnparser.unparseSingleSubstitution(self, lookup)
    140 """Turn a GPOS1 (single substitution) subtable into a fontFeatures Routine."""
    141 b = fontFeatures.Routine(
    142     name=self.getname("SingleSubstitution" + self.gensym())
    143 )
--> 144 self._fix_flags(b, lookup)
    145 for sub in lookup.SubTable:
    146     for k, v in sub.mapping.items():

File ~/.pyenv/versions/3.11.1/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/fontFeatures/ttLib/GTableUnparser.py:273, in GTableUnparser._fix_flags(self, routine, lookup)
    271 if mat:
    272     mat = mat >> 8
--> 273     classDefs = self.font["GDEF"].table.MarkAttachClassDef.classDefs
    274     glyphs = [g for g in classDefs.keys() if classDefs[g] == mat]
    275     routine.markAttachmentSet = glyphs

AttributeError: 'NoneType' object has no attribute 'classDefs'
yanone commented

Wondering whether this should be fixed here or there...

yanone commented

Info: This occurred on 5 fonts out of half of the GF library before I cancelled the test.

If it's failing in fontFeatures, that's a fontFeatures bug... Will fix it there.

I mean to be honest it's a font bug. From the spec, my emphasis:

If MARK_ATTACHMENT_TYPE_MASK is non-zero, then mark attachment classes must be defined in the Mark Attachment Class Definition Table in the GDEF table.

Carlito has a lookup:

        <LookupFlag value="256"/><!-- markAttachmentType[1] -->

but no Mark Attachment Class Definition Table in the GDEF table.

yanone commented

That's why I added that it's only for 5 fonts of the first half that I checked. I would be okay if you didn't fix that in fontFeatures, even though you already fixed the same thing here. Close this issue at your own will.