[ttLib] cmap format 14 cleanup (#1437)

* cleanup cmap format 14 TTX format by removing redundant attributes
* don't output the name attr for a default mapping, instead of a glyph named 'None'
* still accept 'None' as an indicator glyph name, for bw compatibility
* swap order of TTX attrs uv and uvs
* make sure (unicode, glyphName) pairs are always tuples in uvsDict.
This commit is contained in:
Just van Rossum 2019-01-10 19:19:35 +01:00 committed by GitHub
parent 855378477f
commit 6f7c0f1d09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 31 deletions

View File

@ -1135,7 +1135,7 @@ class cmap_format_14(CmapSubtable):
startOffset += 5
uv = cvtToUVS(uv)
glyphName = self.ttFont.getGlyphName(gid)
localUVList.append( [uv, glyphName] )
localUVList.append((uv, glyphName))
try:
uvsDict[varUVS].extend(localUVList)
except KeyError:
@ -1147,9 +1147,6 @@ class cmap_format_14(CmapSubtable):
writer.begintag(self.__class__.__name__, [
("platformID", self.platformID),
("platEncID", self.platEncID),
("format", self.format),
("length", self.length),
("numVarSelectorRecords", self.numVarSelectorRecords),
])
writer.newline()
uvsDict = self.uvsDict
@ -1158,18 +1155,15 @@ class cmap_format_14(CmapSubtable):
uvList = uvsDict[uvs]
uvList.sort(key=lambda item: (item[1] is not None, item[0], item[1]))
for uv, gname in uvList:
if gname is None:
gname = "None"
# I use the arg rather than th keyword syntax in order to preserve the attribute order.
writer.simpletag("map", [ ("uvs",hex(uvs)), ("uv",hex(uv)), ("name", gname)] )
attrs = [("uv", hex(uv)), ("uvs", hex(uvs))]
if gname is not None:
attrs.append(("name", gname))
writer.simpletag("map", attrs)
writer.newline()
writer.endtag(self.__class__.__name__)
writer.newline()
def fromXML(self, name, attrs, content, ttFont):
self.format = safeEval(attrs["format"])
self.length = safeEval(attrs["length"])
self.numVarSelectorRecords = safeEval(attrs["numVarSelectorRecords"])
self.language = 0xFF # provide a value so that CmapSubtable.__lt__() won't fail
if not hasattr(self, "cmap"):
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
@ -1177,6 +1171,11 @@ class cmap_format_14(CmapSubtable):
self.uvsDict = {}
uvsDict = self.uvsDict
# For backwards compatibility reasons we accept "None" as an indicator
# for "default mapping", unless the font actually has a glyph named
# "None".
_hasGlyphNamedNone = None
for element in content:
if not isinstance(element, tuple):
continue
@ -1185,13 +1184,16 @@ class cmap_format_14(CmapSubtable):
continue
uvs = safeEval(attrs["uvs"])
uv = safeEval(attrs["uv"])
gname = attrs["name"]
gname = attrs.get("name")
if gname == "None":
gname = None
if _hasGlyphNamedNone is None:
_hasGlyphNamedNone = "None" in ttFont.getGlyphOrder()
if not _hasGlyphNamedNone:
gname = None
try:
uvsDict[uvs].append( [uv, gname])
uvsDict[uvs].append((uv, gname))
except KeyError:
uvsDict[uvs] = [ [uv, gname] ]
uvsDict[uvs] = [(uv, gname)]
def compile(self, ttFont):
if self.data:

View File

@ -7,9 +7,9 @@
<map code="0x20" name="space"/><!-- SPACE -->
<map code="0x30" name="zero"/><!-- DIGIT ZERO -->
</cmap_format_4>
<cmap_format_14 platformID="0" platEncID="5" format="14" length="49" numVarSelectorRecords="2">
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
<map uvs="0xfe01" uv="0x30" name="None"/>
<cmap_format_14 platformID="0" platEncID="5">
<map uv="0x30" uvs="0xfe00" name="zero.slash"/>
<map uv="0x30" uvs="0xfe01"/>
</cmap_format_14>
<cmap_format_4 platformID="3" platEncID="1" language="0">
<map code="0x20" name="space"/><!-- SPACE -->

View File

@ -11,6 +11,7 @@ from fontTools.ttLib.tables._c_m_a_p import CmapSubtable, table__c_m_a_p
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
DATA_DIR = os.path.join(CURR_DIR, 'data')
CMAP_FORMAT_14_TTX = os.path.join(DATA_DIR, "_c_m_a_p_format_14.ttx")
CMAP_FORMAT_14_BW_COMPAT_TTX = os.path.join(DATA_DIR, "_c_m_a_p_format_14_bw_compat.ttx")
def strip_VariableItems(string):
# ttlib changes with the fontTools version
@ -99,8 +100,8 @@ class CmapSubtableTest(unittest.TestCase):
subtable = self.makeSubtable(14, 0, 5, 0)
subtable.cmap = {} # dummy
subtable.uvsDict = {
0xFE00: [[0x0030, "zero.slash"]],
0xFE01: [(0x0030, None)], # yes, tuple here, list above, to match decompile
0xFE00: [(0x0030, "zero.slash")],
0xFE01: [(0x0030, None)],
}
fb = FontBuilder(1024, isTTF=True)
font = fb.font
@ -122,6 +123,9 @@ class CmapSubtableTest(unittest.TestCase):
with open(CMAP_FORMAT_14_TTX) as f:
expected = strip_VariableItems(f.read())
self.assertEqual(ttx, expected)
with open(CMAP_FORMAT_14_BW_COMPAT_TTX) as f:
font.importXML(f)
self.assertEqual(font["cmap"].getcmap(0, 5).uvsDict, subtable.uvsDict)
if __name__ == "__main__":

View File

@ -3,9 +3,9 @@
<cmap>
<tableVersion version="0"/>
<cmap_format_14 platformID="0" platEncID="5" format="14" length="49" numVarSelectorRecords="2">
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
<map uvs="0xfe01" uv="0x30" name="None"/>
<cmap_format_14 platformID="0" platEncID="5">
<map uv="0x30" uvs="0xfe00" name="zero.slash"/>
<map uv="0x30" uvs="0xfe01"/>
</cmap_format_14>
</cmap>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.35">
<cmap>
<tableVersion version="0"/>
<cmap_format_14 platformID="0" platEncID="5">
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
<map uvs="0xfe01" uv="0x30" name="None"/><!-- testing whether the old format that uses name="None" is still accepted -->
</cmap_format_14>
</cmap>
</ttFont>

View File

@ -3,14 +3,14 @@
<cmap>
<tableVersion version="0"/>
<cmap_format_14 platformID="0" platEncID="5" format="14" length="47" numVarSelectorRecords="1">
<map uvs="0xe0100" uv="0x4e00" name="None"/>
<map uvs="0xe0100" uv="0x4e03" name="None"/>
<map uvs="0xe0100" uv="0x4e04" name="None"/>
<map uvs="0xe0100" uv="0x4e05" name="None"/>
<map uvs="0xe0100" uv="0x4e06" name="None"/>
<map uvs="0xe0100" uv="0x4e10" name="g25"/>
<map uvs="0xe0100" uv="0x4e11" name="g26"/>
<cmap_format_14 platformID="0" platEncID="5">
<map uv="0x4e00" uvs="0xe0100"/>
<map uv="0x4e03" uvs="0xe0100"/>
<map uv="0x4e04" uvs="0xe0100"/>
<map uv="0x4e05" uvs="0xe0100"/>
<map uv="0x4e06" uvs="0xe0100"/>
<map uv="0x4e10" uvs="0xe0100" name="g25"/>
<map uv="0x4e11" uvs="0xe0100" name="g26"/>
</cmap_format_14>
<cmap_format_4 platformID="3" platEncID="1" language="0">
<map code="0x4e00" name="g10"/><!-- CJK UNIFIED IDEOGRAPH-4E00 -->