from fontTools.ttLib import TTFont, newTable, getTableModule from fontTools.ttLib.tables.O_S_2f_2 import * import unittest class OS2TableTest(unittest.TestCase): @staticmethod def makeOS2_cmap(mapping): font = TTFont() font["OS/2"] = os2 = newTable("OS/2") os2.version = 4 font["cmap"] = cmap = newTable("cmap") st = getTableModule("cmap").CmapSubtable.newSubtable(4) st.platformID, st.platEncID, st.language = 3, 1, 0 st.cmap = mapping cmap.tables = [] cmap.tables.append(st) return font, os2, cmap def test_getUnicodeRanges(self): table = table_O_S_2f_2() table.ulUnicodeRange1 = 0xFFFFFFFF table.ulUnicodeRange2 = 0xFFFFFFFF table.ulUnicodeRange3 = 0xFFFFFFFF table.ulUnicodeRange4 = 0xFFFFFFFF bits = table.getUnicodeRanges() for i in range(127): self.assertIn(i, bits) def test_setUnicodeRanges(self): table = table_O_S_2f_2() table.ulUnicodeRange1 = 0 table.ulUnicodeRange2 = 0 table.ulUnicodeRange3 = 0 table.ulUnicodeRange4 = 0 bits = set(range(123)) table.setUnicodeRanges(bits) self.assertEqual(table.getUnicodeRanges(), bits) with self.assertRaises(ValueError): table.setUnicodeRanges([-1, 127, 255]) def test_recalcUnicodeRanges(self): font, os2, cmap = self.makeOS2_cmap( {0x0041: "A", 0x03B1: "alpha", 0x0410: "Acyr"} ) os2.setUnicodeRanges({0, 1, 9}) # 'pruneOnly' will clear any bits for which there's no intersection: # bit 1 ('Latin 1 Supplement'), in this case. However, it won't set # bit 7 ('Greek and Coptic') despite the "alpha" character is present. self.assertEqual(os2.recalcUnicodeRanges(font, pruneOnly=True), {0, 9}) # try again with pruneOnly=False: bit 7 is now set. self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9}) # add a non-BMP char from 'Mahjong Tiles' block (bit 122) cmap.tables[0].cmap[0x1F000] = "eastwindtile" # the bit 122 and the special bit 57 ('Non Plane 0') are also enabled self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9, 57, 122}) def test_intersectUnicodeRanges(self): self.assertEqual(intersectUnicodeRanges([0x0410]), {9}) self.assertEqual(intersectUnicodeRanges([0x0410, 0x1F000]), {9, 57, 122}) self.assertEqual( intersectUnicodeRanges([0x0410, 0x1F000], inverse=True), (set(range(123)) - {9, 57, 122}), ) def test_getCodePageRanges(self): table = table_O_S_2f_2() # version 0 doesn't define these fields so by definition defines no cp ranges table.version = 0 self.assertEqual(table.getCodePageRanges(), set()) # version 1 and above do contain ulCodePageRange1 and 2 fields table.version = 1 table.ulCodePageRange1 = 0xFFFFFFFF table.ulCodePageRange2 = 0xFFFFFFFF bits = table.getCodePageRanges() for i in range(63): self.assertIn(i, bits) def test_setCodePageRanges(self): table = table_O_S_2f_2() table.version = 4 table.ulCodePageRange1 = 0 table.ulCodePageRange2 = 0 bits = set(range(64)) table.setCodePageRanges(bits) self.assertEqual(table.getCodePageRanges(), bits) with self.assertRaises(ValueError): table.setCodePageRanges([-1]) with self.assertRaises(ValueError): table.setCodePageRanges([64]) with self.assertRaises(ValueError): table.setCodePageRanges([255]) def test_setCodePageRanges_bump_version(self): # Setting codepage ranges on a OS/2 table version 0 automatically makes it # a version 1 table table = table_O_S_2f_2() table.version = 0 self.assertEqual(table.getCodePageRanges(), set()) table.setCodePageRanges({0, 1, 2}) self.assertEqual(table.getCodePageRanges(), {0, 1, 2}) self.assertEqual(table.version, 1) def test_recalcCodePageRanges(self): font, os2, cmap = self.makeOS2_cmap( {ord("A"): "A", ord("Ά"): "Alphatonos", ord("Б"): "Be"} ) os2.setCodePageRanges({0, 2, 9}) # With pruneOnly=True, should clear any CodePage for which there are no # characters in the cmap. self.assertEqual(os2.recalcCodePageRanges(font, pruneOnly=True), {2}) # With pruneOnly=False, should also set CodePages not initially set. self.assertEqual(os2.recalcCodePageRanges(font), {2, 3}) # Add a Korean character, should set CodePage 21 (Korean Johab) cmap.tables[0].cmap[ord("곴")] = "goss" self.assertEqual(os2.recalcCodePageRanges(font), {2, 3, 21}) # Remove all characters from cmap, should still set CodePage 0 (Latin 1) cmap.tables[0].cmap = {} self.assertEqual(os2.recalcCodePageRanges(font), {0}) if __name__ == "__main__": import sys sys.exit(unittest.main())