1import io 2import os 3import re 4from fontTools import ttLib 5from fontTools.fontBuilder import FontBuilder 6import unittest 7from fontTools.ttLib.tables._c_m_a_p import CmapSubtable, table__c_m_a_p 8 9CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) 10DATA_DIR = os.path.join(CURR_DIR, 'data') 11CMAP_FORMAT_14_TTX = os.path.join(DATA_DIR, "_c_m_a_p_format_14.ttx") 12CMAP_FORMAT_14_BW_COMPAT_TTX = os.path.join(DATA_DIR, "_c_m_a_p_format_14_bw_compat.ttx") 13 14def strip_VariableItems(string): 15 # ttlib changes with the fontTools version 16 string = re.sub(' ttLibVersion=".*"', '', string) 17 return string 18 19class CmapSubtableTest(unittest.TestCase): 20 21 def makeSubtable(self, cmapFormat, platformID, platEncID, langID): 22 subtable = CmapSubtable.newSubtable(cmapFormat) 23 subtable.platformID, subtable.platEncID, subtable.language = (platformID, platEncID, langID) 24 return subtable 25 26 def test_toUnicode_utf16be(self): 27 subtable = self.makeSubtable(4, 0, 2, 7) 28 self.assertEqual("utf_16_be", subtable.getEncoding()) 29 self.assertEqual(True, subtable.isUnicode()) 30 31 def test_toUnicode_macroman(self): 32 subtable = self.makeSubtable(4, 1, 0, 7) # MacRoman 33 self.assertEqual("mac_roman", subtable.getEncoding()) 34 self.assertEqual(False, subtable.isUnicode()) 35 36 def test_toUnicode_macromanian(self): 37 subtable = self.makeSubtable(4, 1, 0, 37) # Mac Romanian 38 self.assertNotEqual(None, subtable.getEncoding()) 39 self.assertEqual(False, subtable.isUnicode()) 40 41 def test_extended_mac_encodings(self): 42 subtable = self.makeSubtable(4, 1, 1, 0) # Mac Japanese 43 self.assertNotEqual(None, subtable.getEncoding()) 44 self.assertEqual(False, subtable.isUnicode()) 45 46 def test_extended_unknown(self): 47 subtable = self.makeSubtable(4, 10, 11, 12) 48 self.assertEqual(subtable.getEncoding(), None) 49 self.assertEqual(subtable.getEncoding("ascii"), "ascii") 50 self.assertEqual(subtable.getEncoding(default="xyz"), "xyz") 51 52 def test_compile_2(self): 53 subtable = self.makeSubtable(2, 1, 2, 0) 54 subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} 55 font = ttLib.TTFont() 56 font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) 57 data = subtable.compile(font) 58 59 subtable2 = CmapSubtable.newSubtable(2) 60 subtable2.decompile(data, font) 61 self.assertEqual(subtable2.cmap, subtable.cmap) 62 63 def test_compile_2_rebuild_rev_glyph_order(self): 64 for fmt in [2, 4, 12]: 65 subtable = self.makeSubtable(fmt, 1, 2, 0) 66 subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} 67 font = ttLib.TTFont() 68 font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) 69 font._reverseGlyphOrderDict = {} # force first KeyError branch in subtable.compile() 70 data = subtable.compile(font) 71 subtable2 = CmapSubtable.newSubtable(fmt) 72 subtable2.decompile(data, font) 73 self.assertEqual(subtable2.cmap, subtable.cmap, str(fmt)) 74 75 def test_compile_2_gids(self): 76 for fmt in [2, 4, 12]: 77 subtable = self.makeSubtable(fmt, 1, 3, 0) 78 subtable.cmap = {0x0041:'gid001', 0x0042:'gid002'} 79 font = ttLib.TTFont() 80 font.setGlyphOrder([".notdef"]) 81 data = subtable.compile(font) 82 83 def test_compile_decompile_4_empty(self): 84 subtable = self.makeSubtable(4, 3, 1, 0) 85 subtable.cmap = {} 86 font = ttLib.TTFont() 87 font.setGlyphOrder([]) 88 data = subtable.compile(font) 89 subtable2 = CmapSubtable.newSubtable(4) 90 subtable2.decompile(data, font) 91 self.assertEqual(subtable2.cmap, {}) 92 93 def test_decompile_4(self): 94 subtable = CmapSubtable.newSubtable(4) 95 font = ttLib.TTFont() 96 font.setGlyphOrder([]) 97 subtable.decompile(b'\0' * 3 + b'\x10' + b'\0' * 12, font) 98 99 def test_decompile_12(self): 100 subtable = CmapSubtable.newSubtable(12) 101 font = ttLib.TTFont() 102 font.setGlyphOrder([]) 103 subtable.decompile(b'\0' * 7 + b'\x10' + b'\0' * 8, font) 104 105 def test_buildReversed(self): 106 c4 = self.makeSubtable(4, 3, 1, 0) 107 c4.cmap = {0x0041:'A', 0x0391:'A'} 108 c12 = self.makeSubtable(12, 3, 10, 0) 109 c12.cmap = {0x10314: 'u10314'} 110 cmap = table__c_m_a_p() 111 cmap.tables = [c4, c12] 112 self.assertEqual(cmap.buildReversed(), {'A':{0x0041, 0x0391}, 'u10314':{0x10314}}) 113 114 def test_getBestCmap(self): 115 c4 = self.makeSubtable(4, 3, 1, 0) 116 c4.cmap = {0x0041:'A', 0x0391:'A'} 117 c12 = self.makeSubtable(12, 3, 10, 0) 118 c12.cmap = {0x10314: 'u10314'} 119 cmap = table__c_m_a_p() 120 cmap.tables = [c4, c12] 121 self.assertEqual(cmap.getBestCmap(), {0x10314: 'u10314'}) 122 self.assertEqual(cmap.getBestCmap(cmapPreferences=[(3, 1)]), {0x0041:'A', 0x0391:'A'}) 123 self.assertEqual(cmap.getBestCmap(cmapPreferences=[(0, 4)]), None) 124 125 def test_font_getBestCmap(self): 126 c4 = self.makeSubtable(4, 3, 1, 0) 127 c4.cmap = {0x0041:'A', 0x0391:'A'} 128 c12 = self.makeSubtable(12, 3, 10, 0) 129 c12.cmap = {0x10314: 'u10314'} 130 cmap = table__c_m_a_p() 131 cmap.tables = [c4, c12] 132 font = ttLib.TTFont() 133 font["cmap"] = cmap 134 self.assertEqual(font.getBestCmap(), {0x10314: 'u10314'}) 135 self.assertEqual(font.getBestCmap(cmapPreferences=[(3, 1)]), {0x0041:'A', 0x0391:'A'}) 136 self.assertEqual(font.getBestCmap(cmapPreferences=[(0, 4)]), None) 137 138 def test_format_14(self): 139 subtable = self.makeSubtable(14, 0, 5, 0) 140 subtable.cmap = {} # dummy 141 subtable.uvsDict = { 142 0xFE00: [(0x0030, "zero.slash")], 143 0xFE01: [(0x0030, None)], 144 } 145 fb = FontBuilder(1024, isTTF=True) 146 font = fb.font 147 fb.setupGlyphOrder([".notdef", "zero.slash"]) 148 fb.setupMaxp() 149 fb.setupPost() 150 cmap = table__c_m_a_p() 151 cmap.tableVersion = 0 152 cmap.tables = [subtable] 153 font["cmap"] = cmap 154 f = io.BytesIO() 155 font.save(f) 156 f.seek(0) 157 font = ttLib.TTFont(f) 158 self.assertEqual(font["cmap"].getcmap(0, 5).uvsDict, subtable.uvsDict) 159 f = io.StringIO(newline=None) 160 font.saveXML(f, tables=["cmap"]) 161 ttx = strip_VariableItems(f.getvalue()) 162 with open(CMAP_FORMAT_14_TTX) as f: 163 expected = strip_VariableItems(f.read()) 164 self.assertEqual(ttx, expected) 165 with open(CMAP_FORMAT_14_BW_COMPAT_TTX) as f: 166 font.importXML(f) 167 self.assertEqual(font["cmap"].getcmap(0, 5).uvsDict, subtable.uvsDict) 168 169 170if __name__ == "__main__": 171 import sys 172 sys.exit(unittest.main()) 173