def test_bug232(self): # https://github.com/googlefonts/glyphsLib/issues/232 u, g = get_glyph("uni07F0"), get_glyph("longlowtonecomb-nko") self.assertEqual((u.category, g.category), ("Mark", "Mark")) self.assertEqual((u.subCategory, g.subCategory), ("Nonspacing", "Nonspacing")) self.assertEqual((u.production_name, g.production_name), ("uni07F0", "uni07F0")) self.assertEqual((u.unicode, g.unicode), ("07F0", "07F0"))
def generatePy(checkValues, fontAxes, firstGlyph, substitution, bracketDefault, origGlyphName): ''' Verify that the glyph only has one substitution Glyphs App does not appear to support more though this script could serve as a workaround for that. Might add in the future ''' for value in checkValues: glyphString = "" firstRegion = True axis = fontAxes["axis" + str(value.values()[0])]['tag'] if value.keys()[0] != None and bracketDefault == False: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ( "\"%s\" : (%s, %s)" % (axis, str(value.keys()[0]), str(1.0))) firstRegion = False elif value.keys()[0] != None and bracketDefault == True: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ( "\"%s\" : (%s, %s)" % (axis, str(-1.0), str(value.keys()[0]))) firstRegion = False glyphSub = "{\"%s\" : \"%s\"}" % (get_glyph(origGlyphName)[1], get_glyph(origGlyphName)[1] + suffix) print "([{%s}], %s)" % (glyphString, glyphSub) if firstGlyph == True: glyphString = "\t([{%s}], %s)," % (glyphString, glyphSub) else: glyphString = " \n\t([{%s}], %s)," % (glyphString, glyphSub) substitution = substitution + glyphString firstGlyph = False return substitution
def generatePy(checkValues, fontAxes, firstGlyph, substitution, bracketDefault, origGlyphName): ''' Verify that the glyph only has one substitution Glyphs App does not appear to support more though this script could serve as a workaround for that. Might add in the future ''' for value in checkValues: glyphString = "" firstRegion = True axis = fontAxes["axis" + str(value.values()[0])]['tag'] if value.keys()[0] != None and bracketDefault == False: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ("\"%s\" : (%s, %s)" % (axis, str(value.keys()[0]), str(1.0))) firstRegion = False elif value.keys()[0] != None and bracketDefault == True: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ("\"%s\" : (%s, %s)" % (axis, str(-1.0), str(value.keys()[0]))) firstRegion = False glyphSub = "{\"%s\" : \"%s\"}" % (get_glyph(origGlyphName)[1], get_glyph(origGlyphName)[1] + suffix) print "([{%s}], %s)" % (glyphString, glyphSub) if firstGlyph == True: glyphString = "\t([{%s}], %s)," % (glyphString, glyphSub) else: glyphString = " \n\t([{%s}], %s)," % (glyphString, glyphSub) substitution = substitution + glyphString firstGlyph = False return substitution
def test_category(self): cat = lambda n: (get_glyph(n).category, get_glyph(n).subCategory) self.assertEqual(cat(".notdef"), ("Separator", None)) self.assertEqual(cat("uni000D"), ("Separator", None)) self.assertEqual(cat("boxHeavyUp"), ("Symbol", "Geometry")) self.assertEqual(cat("eacute"), ("Letter", "Lowercase")) self.assertEqual(cat("Abreveacute"), ("Letter", "Uppercase")) self.assertEqual(cat("C-fraktur"), ("Letter", "Uppercase")) self.assertEqual(cat("fi"), ("Letter", "Ligature")) self.assertEqual(cat("fi.alt"), ("Letter", "Ligature")) self.assertEqual(cat("hib-ko"), ("Letter", "Syllable")) self.assertEqual(cat("one.foo"), ("Number", "Decimal Digit")) self.assertEqual(cat("one_two.foo"), ("Number", "Ligature")) self.assertEqual(cat("o_f_f_i"), ("Letter", "Ligature")) self.assertEqual(cat("o_f_f_i.foo"), ("Letter", "Ligature")) self.assertEqual(cat("ain_alefMaksura-ar.fina"), ("Letter", "Ligature"))
def test_unicode(self): uni = lambda n: get_glyph(n).unicode self.assertIsNone(uni(".notdef")) self.assertEqual(uni("eacute"), "é") self.assertEqual(uni("Abreveacute"), "Ắ") self.assertEqual(uni("C-fraktur"), "ℭ") self.assertEqual(uni("Dboldscript-math"), "𝓓") self.assertEqual(uni("fi"), "fi") self.assertIsNone(uni("s_t")) # no 'unicode' in GlyphsData self.assertEqual(uni("Gcommaaccent"), "Ģ") self.assertEqual(uni("o_f_f_i.foo"), "offi")
def test_production_name(self): prod = lambda n: get_glyph(n).production_name self.assertEqual(prod(".notdef"), ".notdef") self.assertEqual(prod("eacute"), "eacute") self.assertEqual(prod("Abreveacute"), "uni1EAE") self.assertEqual(prod("C-fraktur"), "uni212D") self.assertEqual(prod("Dboldscript-math"), "u1D4D3") self.assertEqual(prod("fi"), "fi") self.assertEqual(prod("s_t"), "s_t") self.assertEqual(prod("Gcommaaccent"), "uni0122") self.assertEqual(prod("o_f_f_i.foo"), "o_f_f_i.foo")
def test_production_name(self): # Our behavior differs from Glyphs, Glyphs 2.5.2 responses are in comments. prod = lambda n: get_glyph(n).production_name self.assertEqual(prod(".notdef"), ".notdef") self.assertEqual(prod("eacute"), "eacute") self.assertEqual(prod("Abreveacute"), "uni1EAE") self.assertEqual(prod("C-fraktur"), "uni212D") self.assertEqual(prod("Dboldscript-math"), "u1D4D3") self.assertEqual(prod("fi"), "fi") self.assertEqual(prod("s_t"), "s_t") self.assertEqual(prod("Gcommaaccent"), "uni0122") self.assertEqual(prod("o_f_f_i.foo"), "o_f_f_i.foo") self.assertEqual(prod("ain_alefMaksura-ar.fina"), "uniFD13") self.assertEqual(prod("brevecomb"), "uni0306") self.assertEqual(prod("brevecomb.case"), "uni0306.case") self.assertEqual(prod("brevecomb_acutecomb"), "uni03060301") self.assertEqual(prod("brevecomb_acutecomb.case"), "uni03060301.case") self.assertEqual(prod("brevecomb_a_a_a"), "uni0306006100610061") self.assertEqual(prod("brevecomb_a_a_a.case"), "uni0306006100610061.case") self.assertEqual(prod("brevecomb_aaa.case"), "brevecomb_aaa.case") self.assertEqual(prod("brevecomb_Dboldscript-math"), "uni0306_u1D4D3") # brevecomb_Dboldscript-math self.assertEqual( prod("brevecomb_Dboldscript-math.f.r"), "uni0306_u1D4D3.f.r") # brevecomb_Dboldscript-math.f.r self.assertEqual(prod("Dboldscript-math_Dboldscript-math"), "u1D4D3_u1D4D3") self.assertEqual(prod("Dboldscript-math_Dboldscript-math.f"), "u1D4D3_u1D4D3.f") self.assertEqual(prod("Dboldscript-math_a"), "u1D4D3_a") self.assertEqual(prod("a_Dboldscript-math"), "a_u1D4D3") # a_Dboldscript-math self.assertEqual(prod("Dboldscript-math_a_aa"), "u1D4D3_a_uniA733") # Dboldscript-math_a_aa self.assertEqual(prod("Dboldscript-math_a_aaa"), "Dboldscript-math_a_aaa") self.assertEqual(prod("brevecomb_Dboldscript-math"), "uni0306_u1D4D3") # brevecomb_Dboldscript-math self.assertEqual(prod("Dboldscript-math_brevecomb"), "u1D4D3_uni0306") # Dboldscript-math_brevecomb self.assertEqual(prod("idotaccent"), "i.loclTRK") self.assertEqual(prod("a_idotaccent"), "a_i.loclTRK") self.assertEqual(prod("a_idotaccent_a"), "a_idotaccent_a") # a_i.loclTRK_a self.assertEqual(prod("a_a_acutecomb"), "a_a_acutecomb") self.assertEqual(prod("a_a_dieresiscomb"), "uni006100610308") self.assertEqual(prod("brevecomb_acutecomb"), "uni03060301") self.assertEqual(prod("vaphalaa-malayalam"), "uni0D030D35.1")
def __init__(self, path: str): self.font = self._load(path) self.math_tables = {} masters = sorted(self.font.masters, key=lambda m: m.weightValue) self._masters_num = len(masters) self._master_id_indices = {m.id: i for i, m in enumerate(masters)} self.interpolations: dict[str, tuple] = { i.name: [ (self._master_id_indices[id], value) for id, value in i.instanceInterpolations.items() ] for i in self.font.instances if i.active } self.production_names: dict[str, str] = { g.name: glyphdata.get_glyph(g.name).production_name for g in self.font.glyphs } self._decompose_smart_comp()
def test_data(glyphs, data): """Runs checks on the generated GlyphData Makes sure that the implementation of glyphsLib.glyphdata.get_glyph(), if it were to work on the generated GlyphData, will produce the exact same results as the original data files. """ for _, glyph in sorted(glyphs.items()): name = glyph["name"] prod = glyph.get("production", name) unicode = glyph.get("unicode") unicode = unichr(int(unicode, 16)) if unicode else None category = glyph.get("category") subCategory = glyph.get("subCategory") g = get_glyph(name, data=data) assert name == g.name, (name, g.name) assert prod == g.production_name, (name, prod, g.production_name) assert unicode == g.unicode, (name, unicode, g.unicode) assert category == g.category, (name, category, g.category) assert subCategory == g.subCategory, (name, subCategory, g.subCategory)
def to_ufo_glyph(self, ufo_glyph, layer, glyph_data): """Add .glyphs metadata, paths, components, and anchors to a glyph.""" from glyphsLib import glyphdata # Expensive import uval = glyph_data.unicode if uval is not None: ufo_glyph.unicode = int(uval, 16) note = glyph_data.note if note is not None: ufo_glyph.note = note last_change = glyph_data.lastChange if last_change is not None: ufo_glyph.lib[GLYPHLIB_PREFIX + 'lastChange'] = to_ufo_time(last_change) color_index = glyph_data.color if color_index is not None: ufo_glyph.lib[GLYPHLIB_PREFIX + 'ColorIndex'] = color_index color_tuple = None if isinstance(color_index, list): if not all(i in range(0, 256) for i in color_index): logger.warn('Invalid color tuple {} for glyph {}. ' 'Values must be in range 0-255'.format( color_index, glyph_data.name)) else: color_tuple = ','.join( '{0:.4f}'.format(i / 255) if i in range(1, 255) else str(i // 255) for i in color_index) elif isinstance(color_index, int) and color_index in range( len(GLYPHS_COLORS)): color_tuple = GLYPHS_COLORS[color_index] else: logger.warn('Invalid color index {} for {}'.format( color_index, glyph_data.name)) if color_tuple is not None: ufo_glyph.lib[PUBLIC_PREFIX + 'markColor'] = color_tuple export = glyph_data.export if not export: ufo_glyph.lib[GLYPHLIB_PREFIX + 'Export'] = export glyphinfo = glyphdata.get_glyph(ufo_glyph.name) production_name = glyph_data.production or glyphinfo.production_name if production_name != ufo_glyph.name: postscriptNamesKey = PUBLIC_PREFIX + 'postscriptNames' if postscriptNamesKey not in ufo_glyph.font.lib: ufo_glyph.font.lib[postscriptNamesKey] = dict() ufo_glyph.font.lib[postscriptNamesKey][ ufo_glyph.name] = production_name for key in ['leftMetricsKey', 'rightMetricsKey', 'widthMetricsKey']: glyph_metrics_key = getattr(layer, key) if glyph_metrics_key is None: glyph_metrics_key = getattr(glyph_data, key) if glyph_metrics_key: ufo_glyph.lib[GLYPHLIB_PREFIX + key] = glyph_metrics_key # if glyph contains custom 'category' and 'subCategory' overrides, store # them in the UFO glyph's lib category = glyph_data.category if category is None: category = glyphinfo.category else: ufo_glyph.lib[GLYPHLIB_PREFIX + 'category'] = category subCategory = glyph_data.subCategory if subCategory is None: subCategory = glyphinfo.subCategory else: ufo_glyph.lib[GLYPHLIB_PREFIX + 'subCategory'] = subCategory # load width before background, which is loaded with lib data width = layer.width if width is None: pass elif category == 'Mark' and subCategory == 'Nonspacing' and width > 0: # zero the width of Nonspacing Marks like Glyphs.app does on export # TODO: check for customParameter DisableAllAutomaticBehaviour ufo_glyph.lib[GLYPHLIB_PREFIX + 'originalWidth'] = width ufo_glyph.width = 0 else: ufo_glyph.width = width self.to_ufo_glyph_libdata(ufo_glyph, layer) pen = ufo_glyph.getPointPen() self.to_ufo_draw_paths(pen, layer.paths) self.to_ufo_draw_components(pen, layer.components) self.to_ufo_glyph_anchors(ufo_glyph, layer.anchors)
# print axis, value.keys()[0], fontAxes["axis" + str(value.values()[0])]['nMax'], glyphSub # elif value.keys()[0] != None and bracketDefault == True: # print axis, fontAxes["axis" + str(value.values()[0])]['nMin'], value.keys()[0], glyphSub if value.keys()[0] != None and bracketDefault == False: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + "{\"" + axis + "\" : (" + str( value.keys()[0]) + ", " + str(1.0) + ")}" firstRegion = False elif value.keys()[0] != None and bracketDefault == True: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + "{\"" + axis + "\" : (" + str( -1.0) + ", " + str(value.keys()[0]) + ")}" firstRegion = False glyphSub = "{\"" + get_glyph( needsDup[i])[1] + "\"" + " : " + "\"" + get_glyph( needsDup[i])[1] + suffix + "\"}" print "([" + glyphString + "], " + glyphSub + ")" if firstGlyph == True: glyphString = "\t([" + glyphString + "], " + glyphSub + ")," else: glyphString = " \n\t([" + glyphString + "], " + glyphSub + ")," substitution = substitution + glyphString firstGlyph = False # Move this to function? # Delete bracket layers now that they have been made master layers for layerId in delLayer: del font.glyphs[dupGlyph.name].layers[layerId] origGlyph = re.sub(suffix, "", dupGlyph.name)
def uni(n): return get_glyph(n).unicode
# This script should be run from the command line for fixing glyph names that do not get properly converted when building with fontmake # It is recommended to run this on a copy of your .glyphs file import sys import re from glyphsLib.glyphdata import get_glyph from glyphsLib import GSFont filename = sys.argv[-1] font = GSFont(filename) changeName = {} for glyph in font.glyphs: if re.match(".*-.*", get_glyph(glyph.name)[1]) != None: before = glyph.name glyph.name = re.sub("-", "_", glyph.name) after = glyph.name changeName.update({before:after}) for glyph in font.glyphs: for layer in glyph.layers: for component in layer.components: if component.name in changeName: component.name = changeName[component.name] font.save(filename) print "The glyphs: \n %s were renamed as \n %s" % (changeName.keys(), changeName.values())
def to_ufo_glyph(self, ufo_glyph, layer, glyph): """Add .glyphs metadata, paths, components, and anchors to a glyph.""" from glyphsLib import glyphdata # Expensive import ufo_glyph.unicodes = [int(uval, 16) for uval in glyph.unicodes] note = glyph.note if note is not None: ufo_glyph.note = note last_change = glyph.lastChange if last_change is not None: ufo_glyph.lib[GLYPHLIB_PREFIX + "lastChange"] = to_ufo_time(last_change) color_index = glyph.color if color_index is not None: # .3f is enough precision to round-trip uint8 to float losslessly. # https://github.com/unified-font-object/ufo-spec/issues/61 # #issuecomment-389759127 if ( isinstance(color_index, list) and len(color_index) == 4 and all(0 <= v < 256 for v in color_index) ): ufo_glyph.markColor = ",".join( "{:.3f}".format(v / 255) for v in color_index ) elif isinstance(color_index, int) and color_index in range(len(GLYPHS_COLORS)): ufo_glyph.markColor = GLYPHS_COLORS[color_index] else: logger.warning( "Glyph {}, layer {}: Invalid color index/tuple {}".format( glyph.name, layer.name, color_index ) ) export = glyph.export if not export: ufo_glyph.lib[GLYPHLIB_PREFIX + "Export"] = export # FIXME: (jany) next line should be an API of GSGlyph? glyphinfo = glyphdata.get_glyph(ufo_glyph.name) production_name = glyph.production or glyphinfo.production_name if production_name != ufo_glyph.name: postscriptNamesKey = PUBLIC_PREFIX + "postscriptNames" if postscriptNamesKey not in ufo_glyph.font.lib: ufo_glyph.font.lib[postscriptNamesKey] = dict() ufo_glyph.font.lib[postscriptNamesKey][ufo_glyph.name] = production_name for key in ["leftMetricsKey", "rightMetricsKey", "widthMetricsKey"]: value = getattr(layer, key, None) if value: ufo_glyph.lib[GLYPHLIB_PREFIX + "layer." + key] = value value = getattr(glyph, key, None) if value: ufo_glyph.lib[GLYPHLIB_PREFIX + "glyph." + key] = value if glyph.script is not None: ufo_glyph.lib[SCRIPT_LIB_KEY] = glyph.script # if glyph contains custom 'category' and 'subCategory' overrides, store # them in the UFO glyph's lib category = glyph.category if category is None: category = glyphinfo.category else: ufo_glyph.lib[GLYPHLIB_PREFIX + "category"] = category subCategory = glyph.subCategory if subCategory is None: subCategory = glyphinfo.subCategory else: ufo_glyph.lib[GLYPHLIB_PREFIX + "subCategory"] = subCategory # load width before background, which is loaded with lib data width = layer.width if width is None: pass elif category == "Mark" and subCategory == "Nonspacing" and width > 0: # zero the width of Nonspacing Marks like Glyphs.app does on export # TODO: (jany) check for customParameter DisableAllAutomaticBehaviour # FIXME: (jany) also don't do that when rt UFO -> glyphs -> UFO ufo_glyph.lib[ORIGINAL_WIDTH_KEY] = width ufo_glyph.width = 0 else: ufo_glyph.width = width self.to_ufo_background_image(ufo_glyph, layer) self.to_ufo_guidelines(ufo_glyph, layer) self.to_ufo_glyph_background(ufo_glyph, layer) self.to_ufo_annotations(ufo_glyph, layer) self.to_ufo_hints(ufo_glyph, layer) self.to_ufo_glyph_user_data(ufo_glyph.font, glyph) self.to_ufo_layer_user_data(ufo_glyph, layer) self.to_ufo_smart_component_axes(ufo_glyph, glyph) self.to_ufo_paths(ufo_glyph, layer) self.to_ufo_components(ufo_glyph, layer) self.to_ufo_glyph_anchors(ufo_glyph, layer.anchors)
def _build_gdef(ufo): """Build a table GDEF statement for ligature carets.""" from glyphsLib import glyphdata # Expensive import bases, ligatures, marks, carets = set(), set(), set(), {} category_key = GLYPHLIB_PREFIX + 'category' subCategory_key = GLYPHLIB_PREFIX + 'subCategory' for glyph in ufo: has_attaching_anchor = False for anchor in glyph.anchors: name = anchor.name if name and not name.startswith('_'): has_attaching_anchor = True if name and name.startswith('caret_') and 'x' in anchor: carets.setdefault(glyph.name, []).append(round(anchor['x'])) lib = glyph.lib glyphinfo = glyphdata.get_glyph(glyph.name) # first check glyph.lib for category/subCategory overrides; else use # global values from GlyphData category = lib.get(category_key) if category is None: category = glyphinfo.category subCategory = lib.get(subCategory_key) if subCategory is None: subCategory = glyphinfo.subCategory # Glyphs.app assigns glyph classes like this: # # * Base: any glyph that has an attaching anchor # (such as "top"; "_top" does not count) and is neither # classified as Ligature nor Mark using the definitions below; # # * Ligature: if subCategory is "Ligature" and the glyph has # at least one attaching anchor; # # * Mark: if category is "Mark" and subCategory is either # "Nonspacing" or "Spacing Combining"; # # * Compound: never assigned by Glyphs.app. # # https://github.com/googlei18n/glyphsLib/issues/85 # https://github.com/googlei18n/glyphsLib/pull/100#issuecomment-275430289 if subCategory == 'Ligature' and has_attaching_anchor: ligatures.add(glyph.name) elif category == 'Mark' and (subCategory == 'Nonspacing' or subCategory == 'Spacing Combining'): marks.add(glyph.name) elif has_attaching_anchor: bases.add(glyph.name) if not any((bases, ligatures, marks, carets)): return None lines = ['table GDEF {', ' # automatic'] glyphOrder = ufo.lib[PUBLIC_PREFIX + 'glyphOrder'] glyphIndex = lambda glyph: glyphOrder.index(glyph) fmt = lambda g: ('[%s]' % ' '.join(sorted(g, key=glyphIndex))) if g else '' lines.extend([ ' GlyphClassDef', ' %s, # Base' % fmt(bases), ' %s, # Liga' % fmt(ligatures), ' %s, # Mark' % fmt(marks), ' ;']) for glyph, caretPos in sorted(carets.items()): lines.append(' LigatureCaretByPos %s %s;' % (glyph, ' '.join(unicode(p) for p in sorted(caretPos)))) lines.append('} GDEF;') return '\n'.join(lines)
print "ERROR: More than 1 substitution detected for glyph \'%s\'" % needsDup[i] doNotSave = True else: axis = fontAxes["axis" + str(value.values()[0])]['tag'] if value.keys()[0] != None and bracketDefault == False: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ("\"%s\" : (%s, %s)" % (axis, str(value.keys()[0]), str(1.0))) firstRegion = False elif value.keys()[0] != None and bracketDefault == True: if firstRegion == False: glyphString = glyphString + ", " glyphString = glyphString + ("\"%s\" : (%s, %s)" % (axis, str(-1.0), str(value.keys()[0]))) firstRegion = False glyphSub = "{\"%s\" : \"%s\"}" % (get_glyph(needsDup[i])[1], get_glyph(needsDup[i])[1] + suffix) print "([{%s}], %s)" % (glyphString, glyphSub) if firstGlyph == True: glyphString = "\t([{%s}], %s)," % (glyphString, glyphSub) else: glyphString = " \n\t([{%s}], %s)," % (glyphString, glyphSub) substitution = substitution + glyphString firstGlyph = False # Move this to function? # Delete bracket layers now that they have been made master layers for layerId in delLayer: del font.glyphs[dupGlyph.name].layers[layerId] origGlyph = re.sub(suffix, "", dupGlyph.name) del font.glyphs[origGlyph].layers[layerId]
def cat(n): return get_glyph(n).category, get_glyph(n).subCategory
def _build_gdef(ufo): """Build a GDEF table statement (GlyphClassDef and LigatureCaretByPos). Building GlyphClassDef requires anchor propagation or user care to work as expected, as Glyphs.app also looks at anchors for classification: * Base: any glyph that has an attaching anchor (such as "top"; "_top" does not count) and is neither classified as Ligature nor Mark using the definitions below; * Ligature: if subCategory is "Ligature" and the glyph has at least one attaching anchor; * Mark: if category is "Mark" and subCategory is either "Nonspacing" or "Spacing Combining"; * Compound: never assigned by Glyphs.app. See: * https://github.com/googlei18n/glyphsLib/issues/85 * https://github.com/googlei18n/glyphsLib/pull/100#issuecomment-275430289 """ from glyphsLib import glyphdata bases, ligatures, marks, carets = set(), set(), set(), {} category_key = GLYPHLIB_PREFIX + "category" subCategory_key = GLYPHLIB_PREFIX + "subCategory" for glyph in ufo: has_attaching_anchor = False for anchor in glyph.anchors: name = anchor.name if name and not name.startswith("_"): has_attaching_anchor = True if name and name.startswith("caret_") and "x" in anchor: carets.setdefault(glyph.name, []).append(round(anchor["x"])) # First check glyph.lib for category/subCategory overrides. Otherwise, # use global values from GlyphData. glyphinfo = glyphdata.get_glyph(glyph.name) category = glyph.lib.get(category_key) or glyphinfo.category subCategory = glyph.lib.get(subCategory_key) or glyphinfo.subCategory if subCategory == "Ligature" and has_attaching_anchor: ligatures.add(glyph.name) elif category == "Mark" and (subCategory == "Nonspacing" or subCategory == "Spacing Combining"): marks.add(glyph.name) elif has_attaching_anchor: bases.add(glyph.name) if not any((bases, ligatures, marks, carets)): return None def fmt(g): return ("[%s]" % " ".join(sorted(g, key=ufo.glyphOrder.index))) if g else "" lines = [ "table GDEF {", " # automatic", " GlyphClassDef", " %s, # Base" % fmt(bases), " %s, # Liga" % fmt(ligatures), " %s, # Mark" % fmt(marks), " ;", ] for glyph, caretPos in sorted(carets.items()): lines.append(" LigatureCaretByPos %s %s;" % (glyph, " ".join(unicode(p) for p in sorted(caretPos)))) lines.append("} GDEF;") return "\n".join(lines)
def prod(n): return get_glyph(n).production_name