import io import os import re from fontTools import ttLib from fontTools.fontBuilder import FontBuilder import unittest 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 string = re.sub(' ttLibVersion=".*"', "", string) return string class CmapSubtableTest(unittest.TestCase): def makeSubtable(self, cmapFormat, platformID, platEncID, langID): subtable = CmapSubtable.newSubtable(cmapFormat) subtable.platformID, subtable.platEncID, subtable.language = ( platformID, platEncID, langID, ) return subtable def test_toUnicode_utf16be(self): subtable = self.makeSubtable(4, 0, 2, 7) self.assertEqual("utf_16_be", subtable.getEncoding()) self.assertEqual(True, subtable.isUnicode()) def test_toUnicode_macroman(self): subtable = self.makeSubtable(4, 1, 0, 7) # MacRoman self.assertEqual("mac_roman", subtable.getEncoding()) self.assertEqual(False, subtable.isUnicode()) def test_toUnicode_macromanian(self): subtable = self.makeSubtable(4, 1, 0, 37) # Mac Romanian self.assertNotEqual(None, subtable.getEncoding()) self.assertEqual(False, subtable.isUnicode()) def test_extended_mac_encodings(self): subtable = self.makeSubtable(4, 1, 1, 0) # Mac Japanese self.assertNotEqual(None, subtable.getEncoding()) self.assertEqual(False, subtable.isUnicode()) def test_extended_unknown(self): subtable = self.makeSubtable(4, 10, 11, 12) self.assertEqual(subtable.getEncoding(), None) self.assertEqual(subtable.getEncoding("ascii"), "ascii") self.assertEqual(subtable.getEncoding(default="xyz"), "xyz") def test_compile_2(self): subtable = self.makeSubtable(2, 1, 2, 0) subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} font = ttLib.TTFont() font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(2) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, subtable.cmap) def test_compile_2_rebuild_rev_glyph_order(self): for fmt in [2, 4, 12]: subtable = self.makeSubtable(fmt, 1, 2, 0) subtable.cmap = {c: "cid%05d" % c for c in range(32, 8192)} font = ttLib.TTFont() font.setGlyphOrder([".notdef"] + list(subtable.cmap.values())) font._reverseGlyphOrderDict = ( {} ) # force first KeyError branch in subtable.compile() data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(fmt) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, subtable.cmap, str(fmt)) def test_compile_2_gids(self): for fmt in [2, 4, 12]: subtable = self.makeSubtable(fmt, 1, 3, 0) subtable.cmap = {0x0041: "gid001", 0x0042: "gid002"} font = ttLib.TTFont() font.setGlyphOrder([".notdef"]) data = subtable.compile(font) def test_compile_decompile_4_empty(self): subtable = self.makeSubtable(4, 3, 1, 0) subtable.cmap = {} font = ttLib.TTFont() font.setGlyphOrder([]) data = subtable.compile(font) subtable2 = CmapSubtable.newSubtable(4) subtable2.decompile(data, font) self.assertEqual(subtable2.cmap, {}) def test_decompile_4(self): subtable = CmapSubtable.newSubtable(4) font = ttLib.TTFont() font.setGlyphOrder([]) subtable.decompile(b"\0" * 3 + b"\x10" + b"\0" * 12, font) def test_decompile_12(self): subtable = CmapSubtable.newSubtable(12) font = ttLib.TTFont() font.setGlyphOrder([]) subtable.decompile(b"\0" * 7 + b"\x10" + b"\0" * 8, font) def test_buildReversed(self): c4 = self.makeSubtable(4, 3, 1, 0) c4.cmap = {0x0041: "A", 0x0391: "A"} c12 = self.makeSubtable(12, 3, 10, 0) c12.cmap = {0x10314: "u10314"} cmap = table__c_m_a_p() cmap.tables = [c4, c12] self.assertEqual( cmap.buildReversed(), {"A": {0x0041, 0x0391}, "u10314": {0x10314}} ) def test_getBestCmap(self): c4 = self.makeSubtable(4, 3, 1, 0) c4.cmap = {0x0041: "A", 0x0391: "A"} c12 = self.makeSubtable(12, 3, 10, 0) c12.cmap = {0x10314: "u10314"} cmap = table__c_m_a_p() cmap.tables = [c4, c12] self.assertEqual(cmap.getBestCmap(), {0x10314: "u10314"}) self.assertEqual( cmap.getBestCmap(cmapPreferences=[(3, 1)]), {0x0041: "A", 0x0391: "A"} ) self.assertEqual(cmap.getBestCmap(cmapPreferences=[(0, 4)]), None) def test_font_getBestCmap(self): c4 = self.makeSubtable(4, 3, 1, 0) c4.cmap = {0x0041: "A", 0x0391: "A"} c12 = self.makeSubtable(12, 3, 10, 0) c12.cmap = {0x10314: "u10314"} cmap = table__c_m_a_p() cmap.tables = [c4, c12] font = ttLib.TTFont() font["cmap"] = cmap self.assertEqual(font.getBestCmap(), {0x10314: "u10314"}) self.assertEqual( font.getBestCmap(cmapPreferences=[(3, 1)]), {0x0041: "A", 0x0391: "A"} ) self.assertEqual(font.getBestCmap(cmapPreferences=[(0, 4)]), None) def test_format_14(self): subtable = self.makeSubtable(14, 0, 5, 0) subtable.cmap = {} # dummy subtable.uvsDict = { 0xFE00: [(0x0030, "zero.slash")], 0xFE01: [(0x0030, None)], } fb = FontBuilder(1024, isTTF=True) font = fb.font fb.setupGlyphOrder([".notdef", "zero.slash"]) fb.setupMaxp() fb.setupPost() cmap = table__c_m_a_p() cmap.tableVersion = 0 cmap.tables = [subtable] font["cmap"] = cmap f = io.BytesIO() font.save(f) f.seek(0) font = ttLib.TTFont(f) self.assertEqual(font["cmap"].getcmap(0, 5).uvsDict, subtable.uvsDict) f = io.StringIO(newline=None) font.saveXML(f, tables=["cmap"]) ttx = strip_VariableItems(f.getvalue()) 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__": import sys sys.exit(unittest.main())