Fix for #1985: * ensure that the AxisNameID in the STAT table is not less than 256. This needed an additional argument to the addMultiLingualName() name table method. * fvar axis name IDs must also not be less than 256, just like STAT axis names.
This commit is contained in:
parent
df1b499dbc
commit
90c7c7fae1
@ -784,7 +784,7 @@ def _buildAxisRecords(axes, nameTable):
|
|||||||
for axisRecordIndex, axisDict in enumerate(axes):
|
for axisRecordIndex, axisDict in enumerate(axes):
|
||||||
axis = ot.AxisRecord()
|
axis = ot.AxisRecord()
|
||||||
axis.AxisTag = axisDict["tag"]
|
axis.AxisTag = axisDict["tag"]
|
||||||
axis.AxisNameID = _addName(nameTable, axisDict["name"])
|
axis.AxisNameID = _addName(nameTable, axisDict["name"], 256)
|
||||||
axis.AxisOrdering = axisDict.get("ordering", axisRecordIndex)
|
axis.AxisOrdering = axisDict.get("ordering", axisRecordIndex)
|
||||||
axisRecords.append(axis)
|
axisRecords.append(axis)
|
||||||
|
|
||||||
@ -837,7 +837,7 @@ def _buildAxisValuesFormat4(locations, axes, nameTable):
|
|||||||
return axisValues
|
return axisValues
|
||||||
|
|
||||||
|
|
||||||
def _addName(nameTable, value):
|
def _addName(nameTable, value, minNameID=0):
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
# Already a nameID
|
# Already a nameID
|
||||||
return value
|
return value
|
||||||
@ -847,4 +847,4 @@ def _addName(nameTable, value):
|
|||||||
names = value
|
names = value
|
||||||
else:
|
else:
|
||||||
raise TypeError("value must be int, str or dict")
|
raise TypeError("value must be int, str or dict")
|
||||||
return nameTable.addMultilingualName(names)
|
return nameTable.addMultilingualName(names, minNameID=minNameID)
|
||||||
|
@ -184,7 +184,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
raise ValueError("nameID must be less than 32768")
|
raise ValueError("nameID must be less than 32768")
|
||||||
return nameID
|
return nameID
|
||||||
|
|
||||||
def findMultilingualName(self, names, windows=True, mac=True):
|
def findMultilingualName(self, names, windows=True, mac=True, minNameID=0):
|
||||||
"""Return the name ID of an existing multilingual name that
|
"""Return the name ID of an existing multilingual name that
|
||||||
matches the 'names' dictionary, or None if not found.
|
matches the 'names' dictionary, or None if not found.
|
||||||
|
|
||||||
@ -198,6 +198,9 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
platEncID=1.
|
platEncID=1.
|
||||||
If 'mac' is True, the returned name ID is guaranteed to exist
|
If 'mac' is True, the returned name ID is guaranteed to exist
|
||||||
for all requested languages for platformID=1 and platEncID=0.
|
for all requested languages for platformID=1 and platEncID=0.
|
||||||
|
|
||||||
|
The returned name ID will not be less than the 'minNameID'
|
||||||
|
argument.
|
||||||
"""
|
"""
|
||||||
# Gather the set of requested
|
# Gather the set of requested
|
||||||
# (string, platformID, platEncID, langID)
|
# (string, platformID, platEncID, langID)
|
||||||
@ -227,7 +230,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
name.platEncID, name.langID)
|
name.platEncID, name.langID)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
continue
|
continue
|
||||||
if key in reqNameSet:
|
if key in reqNameSet and name.nameID >= minNameID:
|
||||||
nameSet = matchingNames.setdefault(name.nameID, set())
|
nameSet = matchingNames.setdefault(name.nameID, set())
|
||||||
nameSet.add(key)
|
nameSet.add(key)
|
||||||
|
|
||||||
@ -239,7 +242,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
return None # not found
|
return None # not found
|
||||||
|
|
||||||
def addMultilingualName(self, names, ttFont=None, nameID=None,
|
def addMultilingualName(self, names, ttFont=None, nameID=None,
|
||||||
windows=True, mac=True):
|
windows=True, mac=True, minNameID=0):
|
||||||
"""Add a multilingual name, returning its name ID
|
"""Add a multilingual name, returning its name ID
|
||||||
|
|
||||||
'names' is a dictionary with the name in multiple languages,
|
'names' is a dictionary with the name in multiple languages,
|
||||||
@ -258,12 +261,16 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
|
|
||||||
If 'windows' is True, a platformID=3 name record will be added.
|
If 'windows' is True, a platformID=3 name record will be added.
|
||||||
If 'mac' is True, a platformID=1 name record will be added.
|
If 'mac' is True, a platformID=1 name record will be added.
|
||||||
|
|
||||||
|
If the 'nameID' argument is None, the created nameID will not
|
||||||
|
be less than the 'minNameID' argument.
|
||||||
"""
|
"""
|
||||||
if not hasattr(self, 'names'):
|
if not hasattr(self, 'names'):
|
||||||
self.names = []
|
self.names = []
|
||||||
if nameID is None:
|
if nameID is None:
|
||||||
# Reuse nameID if possible
|
# Reuse nameID if possible
|
||||||
nameID = self.findMultilingualName(names, windows=windows, mac=mac)
|
nameID = self.findMultilingualName(
|
||||||
|
names, windows=windows, mac=mac, minNameID=minNameID)
|
||||||
if nameID is not None:
|
if nameID is not None:
|
||||||
return nameID
|
return nameID
|
||||||
nameID = self._findUnusedNameID()
|
nameID = self._findUnusedNameID()
|
||||||
|
@ -71,7 +71,7 @@ def _add_fvar(font, axes, instances):
|
|||||||
axis.axisTag = Tag(a.tag)
|
axis.axisTag = Tag(a.tag)
|
||||||
# TODO Skip axes that have no variation.
|
# TODO Skip axes that have no variation.
|
||||||
axis.minValue, axis.defaultValue, axis.maxValue = a.minimum, a.default, a.maximum
|
axis.minValue, axis.defaultValue, axis.maxValue = a.minimum, a.default, a.maximum
|
||||||
axis.axisNameID = nameTable.addMultilingualName(a.labelNames, font)
|
axis.axisNameID = nameTable.addMultilingualName(a.labelNames, font, minNameID=256)
|
||||||
axis.flags = int(a.hidden)
|
axis.flags = int(a.hidden)
|
||||||
fvar.axes.append(axis)
|
fvar.axes.append(axis)
|
||||||
|
|
||||||
|
@ -1371,6 +1371,11 @@ def test_buildStatTable(axes, axisValues, elidedFallbackName, expected_ttx):
|
|||||||
font = ttLib.TTFont()
|
font = ttLib.TTFont()
|
||||||
font["name"] = ttLib.newTable("name")
|
font["name"] = ttLib.newTable("name")
|
||||||
font["name"].names = []
|
font["name"].names = []
|
||||||
|
# https://github.com/fonttools/fonttools/issues/1985
|
||||||
|
# Add nameID < 256 that matches a test axis name, to test whether
|
||||||
|
# the nameID is not reused: AxisNameIDs must be > 255 according
|
||||||
|
# to the spec.
|
||||||
|
font["name"].addMultilingualName(dict(en="ABCDTest"), nameID=6)
|
||||||
builder.buildStatTable(font, axes, axisValues, elidedFallbackName)
|
builder.buildStatTable(font, axes, axisValues, elidedFallbackName)
|
||||||
f = io.StringIO()
|
f = io.StringIO()
|
||||||
font.saveXML(f, tables=["STAT"])
|
font.saveXML(f, tables=["STAT"])
|
||||||
|
@ -294,6 +294,17 @@ class NameTableTest(unittest.TestCase):
|
|||||||
nameTable.addMultilingualName({"en": "A", "la": "ⱾƤℚⱤ"})
|
nameTable.addMultilingualName({"en": "A", "la": "ⱾƤℚⱤ"})
|
||||||
captor.assertRegex("cannot store language la into 'ltag' table")
|
captor.assertRegex("cannot store language la into 'ltag' table")
|
||||||
|
|
||||||
|
def test_addMultilingualName_minNameID(self):
|
||||||
|
table = table__n_a_m_e()
|
||||||
|
names, namesSubSet, namesSuperSet = self._get_test_names()
|
||||||
|
nameID = table.addMultilingualName(names, nameID=2)
|
||||||
|
self.assertEqual(nameID, 2)
|
||||||
|
nameID = table.addMultilingualName(names)
|
||||||
|
self.assertEqual(nameID, 2)
|
||||||
|
nameID = table.addMultilingualName(names, minNameID=256)
|
||||||
|
self.assertGreaterEqual(nameID, 256)
|
||||||
|
self.assertEqual(nameID, table.findMultilingualName(names, minNameID=256))
|
||||||
|
|
||||||
def test_decompile_badOffset(self):
|
def test_decompile_badOffset(self):
|
||||||
# https://github.com/fonttools/fonttools/issues/525
|
# https://github.com/fonttools/fonttools/issues/525
|
||||||
table = table__n_a_m_e()
|
table = table__n_a_m_e()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user