Skip to content

Commit

Permalink
Construct glyph data from unicodes as a fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
yanone committed Oct 21, 2021
1 parent 6b4e8d7 commit 1f44699
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Lib/glyphsLib/builder/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _build_gdef(ufo, skipExportGlyphs=None):

# First check glyph.lib for category/subCategory overrides. Otherwise,
# use global values from GlyphData.
glyphinfo = glyphdata.get_glyph(glyph.name)
glyphinfo = glyphdata.get_glyph(glyph.name, [f"{c:04X}" for c in glyph.unicodes])
category = glyph.lib.get(category_key) or glyphinfo.category
subCategory = glyph.lib.get(subCategory_key) or glyphinfo.subCategory

Expand Down
4 changes: 2 additions & 2 deletions Lib/glyphsLib/builder/glyph.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def to_ufo_glyph(self, ufo_glyph, layer, glyph): # noqa: C901
ufo_glyph.lib[GLYPHLIB_PREFIX + "Export"] = export

# FIXME: (jany) next line should be an API of GSGlyph?
glyphinfo = glyphsLib.glyphdata.get_glyph(ufo_glyph.name)
glyphinfo = glyphsLib.glyphdata.get_glyph(ufo_glyph.name, glyph.unicodes)
if glyph.production:
production_name = glyph.production
# Make sure production names of bracket glyphs also get a BRACKET suffix.
Expand Down Expand Up @@ -283,7 +283,7 @@ def to_glyphs_glyph(self, ufo_glyph, ufo_layer, master): # noqa: C901
# glyphinfo = glyphsLib.glyphdata.get_glyph(ufo_glyph.name)
# production_name = glyph.production or glyphinfo.production_name

glyphinfo = glyphsLib.glyphdata.get_glyph(ufo_glyph.name)
glyphinfo = glyphsLib.glyphdata.get_glyph(ufo_glyph.name, glyph.unicodes)

layer = self.to_glyphs_layer(ufo_layer, glyph, master)

Expand Down
30 changes: 25 additions & 5 deletions Lib/glyphsLib/glyphdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,29 @@ class GlyphData:
dictionaries.
"""

__slots__ = ["names", "alternative_names", "production_names"]
__slots__ = ["names", "alternative_names", "production_names", "unicodes"]

def __init__(self, name_mapping, alt_name_mapping, production_name_mapping):
def __init__(self, name_mapping, alt_name_mapping, production_name_mapping, unicodes_mapping):
self.names = name_mapping
self.alternative_names = alt_name_mapping
self.production_names = production_name_mapping
self.unicodes = unicodes_mapping

@classmethod
def from_files(cls, *glyphdata_files):
"""Return GlyphData holding data from a list of XML file paths."""
name_mapping = {}
alt_name_mapping = {}
production_name_mapping = {}
unicodes_mapping = {}

for glyphdata_file in glyphdata_files:
glyph_data = xml.etree.ElementTree.parse(glyphdata_file).getroot()
for glyph in glyph_data:
glyph_name = glyph.attrib["name"]
glyph_name_alternatives = glyph.attrib.get("altNames")
glyph_name_production = glyph.attrib.get("production")
glyph_unicode = glyph.attrib.get("unicode")

name_mapping[glyph_name] = glyph.attrib
if glyph_name_alternatives:
Expand All @@ -78,16 +81,18 @@ def from_files(cls, *glyphdata_files):
alt_name_mapping[glyph_name_alternative] = glyph.attrib
if glyph_name_production:
production_name_mapping[glyph_name_production] = glyph.attrib
if glyph_unicode:
unicodes_mapping[glyph_unicode] = glyph.attrib

return cls(name_mapping, alt_name_mapping, production_name_mapping)
return cls(name_mapping, alt_name_mapping, production_name_mapping, unicodes_mapping)


def get_glyph(glyph_name, data=None):
def get_glyph(glyph_name, unicodes=[], data=None):
"""Return a named tuple (Glyph) containing information derived from a glyph
name akin to GSGlyphInfo.
The information is derived from an included copy of GlyphData.xml
and GlyphData_Ideographs.xml, going purely by the glyph name.
and GlyphData_Ideographs.xml, going by the glyph name or unicode fallback.
"""

# Read data on first use.
Expand All @@ -105,6 +110,13 @@ def get_glyph(glyph_name, data=None):
# Look up data by full glyph name first.
attributes = _lookup_attributes(glyph_name, data)

# Look up by unicode
if attributes == {} and unicodes:
for unicode in unicodes:
attributes = _lookup_attributes_by_unicode(unicode, data)
if attributes:
break

production_name = attributes.get("production")
if production_name is None:
production_name = _construct_production_name(glyph_name, data=data)
Expand Down Expand Up @@ -147,6 +159,14 @@ def _lookup_attributes(glyph_name, data):
return attributes


def _lookup_attributes_by_unicode(unicode, data):
"""Look up glyph attributes in data by unicode
or return empty dictionary.
"""
attributes = data.unicodes.get(unicode) or {}
return attributes


def _agl_compliant_name(glyph_name):
"""Return an AGL-compliant name string or None if we can't make one."""
MAX_GLYPH_NAME_LENGTH = 63
Expand Down
7 changes: 7 additions & 0 deletions tests/glyphdata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ def cat(n):
self.assertEqual(cat("dal_alef-ar"), ("Letter", "Ligature"))
self.assertEqual(cat("dal_lam-ar.dlig"), ("Letter", "Ligature"))

def test_category_buy_unicode(self):
def cat(n, u):
return get_glyph(n, u).category, get_glyph(n, u).subCategory

# "SignU.bn" is a non-standard name not defined in GlyphData.xml
self.assertEqual(cat("SignU.bn", ["09C1"]), ("Mark", "Nonspacing"))

def test_bug232(self):
# https://github.com/googlefonts/glyphsLib/issues/232
u, g = get_glyph("uni07F0"), get_glyph("longlowtonecomb-nko")
Expand Down

0 comments on commit 1f44699

Please sign in to comment.