from __future__ import print_function, division, absolute_import, unicode_literals from fontTools.misc.py23 import * from fontTools.misc.testTools import parseXML, getXML from fontTools.misc.textTools import deHexStr from fontTools.ttLib import TTFont, TTLibError from fontTools.ttLib.tables._t_r_a_k import * from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e, NameRecord import unittest # /Library/Fonts/Osaka.ttf from OSX has trak table with both horiz and vertData OSAKA_TRAK_TABLE_DATA = deHexStr( '00 01 00 00 00 00 00 0c 00 40 00 00 00 03 00 02 00 00 00 2c ff ff ' '00 00 01 06 00 34 00 00 00 00 01 07 00 38 00 01 00 00 01 08 00 3c ' '00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 00 00 00 0c 00 0c 00 03 ' '00 02 00 00 00 60 ff ff 00 00 01 09 00 68 00 00 00 00 01 0a 00 6c ' '00 01 00 00 01 0b 00 70 00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 ' '00 00 00 0c 00 0c') # decompiled horizData and vertData entries from Osaka.ttf OSAKA_HORIZ_TRACK_ENTRIES = { -1.0: TrackTableEntry({24.0: -12, 12.0: -12}, nameIndex=262), 0.0: TrackTableEntry({24.0: 0, 12.0: 0}, nameIndex=263), 1.0: TrackTableEntry({24.0: 12, 12.0: 12}, nameIndex=264) } OSAKA_VERT_TRACK_ENTRIES = { -1.0: TrackTableEntry({24.0: -12, 12.0: -12}, nameIndex=265), 0.0: TrackTableEntry({24.0: 0, 12.0: 0}, nameIndex=266), 1.0: TrackTableEntry({24.0: 12, 12.0: 12}, nameIndex=267) } OSAKA_TRAK_TABLE_XML = [ '', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', ] # made-up table containing only vertData (no horizData) OSAKA_VERT_ONLY_TRAK_TABLE_DATA = deHexStr( '00 01 00 00 00 00 00 00 00 0c 00 00 00 03 00 02 00 00 00 2c ff ff ' '00 00 01 09 00 34 00 00 00 00 01 0a 00 38 00 01 00 00 01 0b 00 3c ' '00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 00 00 00 0c 00 0c') OSAKA_VERT_ONLY_TRAK_TABLE_XML = [ '', '', '', ' ', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', ] # also /Library/Fonts/Skia.ttf contains a trak table with horizData SKIA_TRAK_TABLE_DATA = deHexStr( '00 01 00 00 00 00 00 0c 00 00 00 00 00 03 00 05 00 00 00 2c ff ff ' '00 00 01 13 00 40 00 00 00 00 01 2f 00 4a 00 01 00 00 01 14 00 54 ' '00 09 00 00 00 0a 00 00 00 0c 00 00 00 12 00 00 00 13 00 00 ff f6 ' 'ff e2 ff c4 ff c1 ff c1 00 0f 00 00 ff fb ff e7 ff e7 00 8c 00 82 ' '00 7d 00 73 00 73') SKIA_TRACK_ENTRIES = { -1.0: TrackTableEntry( {9.0: -10, 10.0: -30, 19.0: -63, 12.0: -60, 18.0: -63}, nameIndex=275), 0.0: TrackTableEntry( {9.0: 15, 10.0: 0, 19.0: -25, 12.0: -5, 18.0: -25}, nameIndex=303), 1.0: TrackTableEntry( {9.0: 140, 10.0: 130, 19.0: 115, 12.0: 125, 18.0: 115}, nameIndex=276) } SKIA_TRAK_TABLE_XML = [ '', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', '', ' ', '', ] class TrackingTableTest(unittest.TestCase): def __init__(self, methodName): unittest.TestCase.__init__(self, methodName) # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, # and fires deprecation warnings if a program uses the old name. if not hasattr(self, "assertRaisesRegex"): self.assertRaisesRegex = self.assertRaisesRegexp def setUp(self): table = table__t_r_a_k() table.version = 1.0 table.format = 0 self.font = {'trak': table} def test_compile_horiz(self): table = self.font['trak'] table.horizData = TrackData(SKIA_TRACK_ENTRIES) trakData = table.compile(self.font) self.assertEqual(trakData, SKIA_TRAK_TABLE_DATA) def test_compile_vert(self): table = self.font['trak'] table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES) trakData = table.compile(self.font) self.assertEqual(trakData, OSAKA_VERT_ONLY_TRAK_TABLE_DATA) def test_compile_horiz_and_vert(self): table = self.font['trak'] table.horizData = TrackData(OSAKA_HORIZ_TRACK_ENTRIES) table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES) trakData = table.compile(self.font) self.assertEqual(trakData, OSAKA_TRAK_TABLE_DATA) def test_compile_longword_aligned(self): table = self.font['trak'] # without padding, this 'horizData' would end up 46 byte long table.horizData = TrackData({ 0.0: TrackTableEntry(nameIndex=256, values={12.0: 0, 24.0: 0, 36.0: 0}) }) table.vertData = TrackData({ 0.0: TrackTableEntry(nameIndex=257, values={12.0: 0, 24.0: 0, 36.0: 0}) }) trakData = table.compile(self.font) self.assertTrue(table.vertOffset % 4 == 0) def test_compile_sizes_mismatch(self): table = self.font['trak'] table.horizData = TrackData({ -1.0: TrackTableEntry(nameIndex=256, values={9.0: -10, 10.0: -30}), 0.0: TrackTableEntry(nameIndex=257, values={8.0: 20, 12.0: 0}) }) with self.assertRaisesRegex(TTLibError, 'entries must specify the same sizes'): table.compile(self.font) def test_decompile_horiz(self): table = self.font['trak'] table.decompile(SKIA_TRAK_TABLE_DATA, self.font) self.assertEqual(table.horizData, SKIA_TRACK_ENTRIES) self.assertEqual(table.vertData, TrackData()) def test_decompile_vert(self): table = self.font['trak'] table.decompile(OSAKA_VERT_ONLY_TRAK_TABLE_DATA, self.font) self.assertEqual(table.horizData, TrackData()) self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES) def test_decompile_horiz_and_vert(self): table = self.font['trak'] table.decompile(OSAKA_TRAK_TABLE_DATA, self.font) self.assertEqual(table.horizData, OSAKA_HORIZ_TRACK_ENTRIES) self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES) def test_roundtrip_decompile_compile(self): for trakData in ( OSAKA_TRAK_TABLE_DATA, OSAKA_VERT_ONLY_TRAK_TABLE_DATA, SKIA_TRAK_TABLE_DATA): table = table__t_r_a_k() table.decompile(trakData, ttFont=None) newTrakData = table.compile(ttFont=None) self.assertEqual(trakData, newTrakData) def test_fromXML_horiz(self): table = self.font['trak'] for name, attrs, content in parseXML(SKIA_TRAK_TABLE_XML): table.fromXML(name, attrs, content, self.font) self.assertEqual(table.version, 1.0) self.assertEqual(table.format, 0) self.assertEqual(table.horizData, SKIA_TRACK_ENTRIES) self.assertEqual(table.vertData, TrackData()) def test_fromXML_horiz_and_vert(self): table = self.font['trak'] for name, attrs, content in parseXML(OSAKA_TRAK_TABLE_XML): table.fromXML(name, attrs, content, self.font) self.assertEqual(table.version, 1.0) self.assertEqual(table.format, 0) self.assertEqual(table.horizData, OSAKA_HORIZ_TRACK_ENTRIES) self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES) def test_fromXML_vert(self): table = self.font['trak'] for name, attrs, content in parseXML(OSAKA_VERT_ONLY_TRAK_TABLE_XML): table.fromXML(name, attrs, content, self.font) self.assertEqual(table.version, 1.0) self.assertEqual(table.format, 0) self.assertEqual(table.horizData, TrackData()) self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES) def test_toXML_horiz(self): table = self.font['trak'] table.horizData = TrackData(SKIA_TRACK_ENTRIES) add_name(self.font, 'Tight', nameID=275) add_name(self.font, 'Normal', nameID=303) add_name(self.font, 'Loose', nameID=276) self.assertEqual( SKIA_TRAK_TABLE_XML, getXML(table.toXML, self.font)) def test_toXML_horiz_and_vert(self): table = self.font['trak'] table.horizData = TrackData(OSAKA_HORIZ_TRACK_ENTRIES) table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES) add_name(self.font, 'Tight', nameID=262) add_name(self.font, 'Normal', nameID=263) add_name(self.font, 'Loose', nameID=264) add_name(self.font, 'Tight', nameID=265) add_name(self.font, 'Normal', nameID=266) add_name(self.font, 'Loose', nameID=267) self.assertEqual( OSAKA_TRAK_TABLE_XML, getXML(table.toXML, self.font)) def test_toXML_vert(self): table = self.font['trak'] table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES) add_name(self.font, 'Tight', nameID=265) add_name(self.font, 'Normal', nameID=266) add_name(self.font, 'Loose', nameID=267) self.assertEqual( OSAKA_VERT_ONLY_TRAK_TABLE_XML, getXML(table.toXML, self.font)) def test_roundtrip_fromXML_toXML(self): font = {} add_name(font, 'Tight', nameID=275) add_name(font, 'Normal', nameID=303) add_name(font, 'Loose', nameID=276) add_name(font, 'Tight', nameID=262) add_name(font, 'Normal', nameID=263) add_name(font, 'Loose', nameID=264) add_name(font, 'Tight', nameID=265) add_name(font, 'Normal', nameID=266) add_name(font, 'Loose', nameID=267) for input_xml in ( SKIA_TRAK_TABLE_XML, OSAKA_TRAK_TABLE_XML, OSAKA_VERT_ONLY_TRAK_TABLE_XML): table = table__t_r_a_k() font['trak'] = table for name, attrs, content in parseXML(input_xml): table.fromXML(name, attrs, content, font) output_xml = getXML(table.toXML, font) self.assertEqual(input_xml, output_xml) def add_name(font, string, nameID): nameTable = font.get("name") if nameTable is None: nameTable = font["name"] = table__n_a_m_e() nameTable.names = [] namerec = NameRecord() namerec.nameID = nameID namerec.string = string.encode('mac_roman') namerec.platformID, namerec.platEncID, namerec.langID = (1, 0, 0) nameTable.names.append(namerec) if __name__ == "__main__": import sys sys.exit(unittest.main())