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