[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:
parent
855378477f
commit
6f7c0f1d09
@ -1135,7 +1135,7 @@ class cmap_format_14(CmapSubtable):
|
|||||||
startOffset += 5
|
startOffset += 5
|
||||||
uv = cvtToUVS(uv)
|
uv = cvtToUVS(uv)
|
||||||
glyphName = self.ttFont.getGlyphName(gid)
|
glyphName = self.ttFont.getGlyphName(gid)
|
||||||
localUVList.append( [uv, glyphName] )
|
localUVList.append((uv, glyphName))
|
||||||
try:
|
try:
|
||||||
uvsDict[varUVS].extend(localUVList)
|
uvsDict[varUVS].extend(localUVList)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -1147,9 +1147,6 @@ class cmap_format_14(CmapSubtable):
|
|||||||
writer.begintag(self.__class__.__name__, [
|
writer.begintag(self.__class__.__name__, [
|
||||||
("platformID", self.platformID),
|
("platformID", self.platformID),
|
||||||
("platEncID", self.platEncID),
|
("platEncID", self.platEncID),
|
||||||
("format", self.format),
|
|
||||||
("length", self.length),
|
|
||||||
("numVarSelectorRecords", self.numVarSelectorRecords),
|
|
||||||
])
|
])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
uvsDict = self.uvsDict
|
uvsDict = self.uvsDict
|
||||||
@ -1158,18 +1155,15 @@ class cmap_format_14(CmapSubtable):
|
|||||||
uvList = uvsDict[uvs]
|
uvList = uvsDict[uvs]
|
||||||
uvList.sort(key=lambda item: (item[1] is not None, item[0], item[1]))
|
uvList.sort(key=lambda item: (item[1] is not None, item[0], item[1]))
|
||||||
for uv, gname in uvList:
|
for uv, gname in uvList:
|
||||||
if gname is None:
|
attrs = [("uv", hex(uv)), ("uvs", hex(uvs))]
|
||||||
gname = "None"
|
if gname is not None:
|
||||||
# I use the arg rather than th keyword syntax in order to preserve the attribute order.
|
attrs.append(("name", gname))
|
||||||
writer.simpletag("map", [ ("uvs",hex(uvs)), ("uv",hex(uv)), ("name", gname)] )
|
writer.simpletag("map", attrs)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
writer.endtag(self.__class__.__name__)
|
writer.endtag(self.__class__.__name__)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
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
|
self.language = 0xFF # provide a value so that CmapSubtable.__lt__() won't fail
|
||||||
if not hasattr(self, "cmap"):
|
if not hasattr(self, "cmap"):
|
||||||
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
|
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 = {}
|
self.uvsDict = {}
|
||||||
uvsDict = 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:
|
for element in content:
|
||||||
if not isinstance(element, tuple):
|
if not isinstance(element, tuple):
|
||||||
continue
|
continue
|
||||||
@ -1185,13 +1184,16 @@ class cmap_format_14(CmapSubtable):
|
|||||||
continue
|
continue
|
||||||
uvs = safeEval(attrs["uvs"])
|
uvs = safeEval(attrs["uvs"])
|
||||||
uv = safeEval(attrs["uv"])
|
uv = safeEval(attrs["uv"])
|
||||||
gname = attrs["name"]
|
gname = attrs.get("name")
|
||||||
if gname == "None":
|
if gname == "None":
|
||||||
gname = None
|
if _hasGlyphNamedNone is None:
|
||||||
|
_hasGlyphNamedNone = "None" in ttFont.getGlyphOrder()
|
||||||
|
if not _hasGlyphNamedNone:
|
||||||
|
gname = None
|
||||||
try:
|
try:
|
||||||
uvsDict[uvs].append( [uv, gname])
|
uvsDict[uvs].append((uv, gname))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
uvsDict[uvs] = [ [uv, gname] ]
|
uvsDict[uvs] = [(uv, gname)]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if self.data:
|
if self.data:
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
<map code="0x20" name="space"/><!-- SPACE -->
|
<map code="0x20" name="space"/><!-- SPACE -->
|
||||||
<map code="0x30" name="zero"/><!-- DIGIT ZERO -->
|
<map code="0x30" name="zero"/><!-- DIGIT ZERO -->
|
||||||
</cmap_format_4>
|
</cmap_format_4>
|
||||||
<cmap_format_14 platformID="0" platEncID="5" format="14" length="49" numVarSelectorRecords="2">
|
<cmap_format_14 platformID="0" platEncID="5">
|
||||||
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
|
<map uv="0x30" uvs="0xfe00" name="zero.slash"/>
|
||||||
<map uvs="0xfe01" uv="0x30" name="None"/>
|
<map uv="0x30" uvs="0xfe01"/>
|
||||||
</cmap_format_14>
|
</cmap_format_14>
|
||||||
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
||||||
<map code="0x20" name="space"/><!-- SPACE -->
|
<map code="0x20" name="space"/><!-- SPACE -->
|
||||||
|
@ -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__)))
|
CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
|
||||||
DATA_DIR = os.path.join(CURR_DIR, 'data')
|
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_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):
|
def strip_VariableItems(string):
|
||||||
# ttlib changes with the fontTools version
|
# ttlib changes with the fontTools version
|
||||||
@ -99,8 +100,8 @@ class CmapSubtableTest(unittest.TestCase):
|
|||||||
subtable = self.makeSubtable(14, 0, 5, 0)
|
subtable = self.makeSubtable(14, 0, 5, 0)
|
||||||
subtable.cmap = {} # dummy
|
subtable.cmap = {} # dummy
|
||||||
subtable.uvsDict = {
|
subtable.uvsDict = {
|
||||||
0xFE00: [[0x0030, "zero.slash"]],
|
0xFE00: [(0x0030, "zero.slash")],
|
||||||
0xFE01: [(0x0030, None)], # yes, tuple here, list above, to match decompile
|
0xFE01: [(0x0030, None)],
|
||||||
}
|
}
|
||||||
fb = FontBuilder(1024, isTTF=True)
|
fb = FontBuilder(1024, isTTF=True)
|
||||||
font = fb.font
|
font = fb.font
|
||||||
@ -122,6 +123,9 @@ class CmapSubtableTest(unittest.TestCase):
|
|||||||
with open(CMAP_FORMAT_14_TTX) as f:
|
with open(CMAP_FORMAT_14_TTX) as f:
|
||||||
expected = strip_VariableItems(f.read())
|
expected = strip_VariableItems(f.read())
|
||||||
self.assertEqual(ttx, expected)
|
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__":
|
if __name__ == "__main__":
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
<cmap>
|
<cmap>
|
||||||
<tableVersion version="0"/>
|
<tableVersion version="0"/>
|
||||||
<cmap_format_14 platformID="0" platEncID="5" format="14" length="49" numVarSelectorRecords="2">
|
<cmap_format_14 platformID="0" platEncID="5">
|
||||||
<map uvs="0xfe00" uv="0x30" name="zero.slash"/>
|
<map uv="0x30" uvs="0xfe00" name="zero.slash"/>
|
||||||
<map uvs="0xfe01" uv="0x30" name="None"/>
|
<map uv="0x30" uvs="0xfe01"/>
|
||||||
</cmap_format_14>
|
</cmap_format_14>
|
||||||
</cmap>
|
</cmap>
|
||||||
|
|
||||||
|
12
Tests/ttLib/tables/data/_c_m_a_p_format_14_bw_compat.ttx
Normal file
12
Tests/ttLib/tables/data/_c_m_a_p_format_14_bw_compat.ttx
Normal 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>
|
@ -3,14 +3,14 @@
|
|||||||
|
|
||||||
<cmap>
|
<cmap>
|
||||||
<tableVersion version="0"/>
|
<tableVersion version="0"/>
|
||||||
<cmap_format_14 platformID="0" platEncID="5" format="14" length="47" numVarSelectorRecords="1">
|
<cmap_format_14 platformID="0" platEncID="5">
|
||||||
<map uvs="0xe0100" uv="0x4e00" name="None"/>
|
<map uv="0x4e00" uvs="0xe0100"/>
|
||||||
<map uvs="0xe0100" uv="0x4e03" name="None"/>
|
<map uv="0x4e03" uvs="0xe0100"/>
|
||||||
<map uvs="0xe0100" uv="0x4e04" name="None"/>
|
<map uv="0x4e04" uvs="0xe0100"/>
|
||||||
<map uvs="0xe0100" uv="0x4e05" name="None"/>
|
<map uv="0x4e05" uvs="0xe0100"/>
|
||||||
<map uvs="0xe0100" uv="0x4e06" name="None"/>
|
<map uv="0x4e06" uvs="0xe0100"/>
|
||||||
<map uvs="0xe0100" uv="0x4e10" name="g25"/>
|
<map uv="0x4e10" uvs="0xe0100" name="g25"/>
|
||||||
<map uvs="0xe0100" uv="0x4e11" name="g26"/>
|
<map uv="0x4e11" uvs="0xe0100" name="g26"/>
|
||||||
</cmap_format_14>
|
</cmap_format_14>
|
||||||
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
||||||
<map code="0x4e00" name="g10"/><!-- CJK UNIFIED IDEOGRAPH-4E00 -->
|
<map code="0x4e00" name="g10"/><!-- CJK UNIFIED IDEOGRAPH-4E00 -->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user