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